3fb01fd5B-UeibZkmSCOUZckNyNFYA tools/internal/xi_vbd_list.c
3f86be322bd0h9jG3krZFOUgCDoxZg tools/internal/xi_vif_params.c
3eb781fd7211MZsLxJSiuy7W4KnJXg tools/internal/xi_vifinit
-3fbba6dbDfYvJSsw9500b4SZyUhxjQ tools/libxi/Makefile
-3fbba6dbEVkVMX0JuDFzap9jeaucGA tools/libxi/libxi_bvtsched.c
-3fbba6dbasJQV-MVElDC0DGSHMiL5w tools/libxi/libxi_domain.c
-3fbba6dbNCU7U6nsMYiXzKkp3ztaJg tools/libxi/libxi_linux_build.c
-3fbba6dbl267zZOAVHYLOdLCdhcZMw tools/libxi/libxi_linux_restore.c
-3fbba6db7li3FJiABYtCmuGxOJxEGw tools/libxi/libxi_linux_save.c
-3fbba6db7WnnJr0KFrIFrqNlSKvFYg tools/libxi/libxi_misc.c
-3fbba6dctWRWlFJkYb6hdix2X4WMuw tools/libxi/libxi_private.c
-3fbba6dcbVrG2hPzEzwdeV_UC8kydQ tools/libxi/libxi_private.h
-3fbba6dcoGq9hQlksrBUfC2P5F6sGg tools/libxi/libxi_vbd.c
-3fbba6dc38q-ioRlwSR_quw4G3qUeQ tools/libxi/libxi_vif.c
-3fbba6dc1uU7U3IFeF6A-XEOYF2MkQ tools/libxi/rpm.spec
-3fbba6dcrNxtygEcgJYAJJ1gCQqfsA tools/libxi/xi.h
+3fbba6dbDfYvJSsw9500b4SZyUhxjQ tools/libxc/Makefile
+3fbba6dbEVkVMX0JuDFzap9jeaucGA tools/libxc/libxc_bvtsched.c
+3fbba6dbasJQV-MVElDC0DGSHMiL5w tools/libxc/libxc_domain.c
+3fbba6dbNCU7U6nsMYiXzKkp3ztaJg tools/libxc/libxc_linux_build.c
+3fbba6dbl267zZOAVHYLOdLCdhcZMw tools/libxc/libxc_linux_restore.c
+3fbba6db7li3FJiABYtCmuGxOJxEGw tools/libxc/libxc_linux_save.c
+3fbba6db7WnnJr0KFrIFrqNlSKvFYg tools/libxc/libxc_misc.c
+3fbba6dctWRWlFJkYb6hdix2X4WMuw tools/libxc/libxc_private.c
+3fbba6dcbVrG2hPzEzwdeV_UC8kydQ tools/libxc/libxc_private.h
+3fbba6dcoGq9hQlksrBUfC2P5F6sGg tools/libxc/libxc_vbd.c
+3fbba6dc38q-ioRlwSR_quw4G3qUeQ tools/libxc/libxc_vif.c
+3fbba6dc1uU7U3IFeF6A-XEOYF2MkQ tools/libxc/rpm.spec
+3fbba6dcrNxtygEcgJYAJJ1gCQqfsA tools/libxc/xc.h
3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile
3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile
3f6dc140C8tAeBfroAF24VrmCS4v_w tools/misc/miniterm/README
--- /dev/null
+
+CC = gcc
+CFLAGS = -c -Wall -O3
+CFLAGS += -I../../xen/include -I../../xenolinux-sparse/include
+
+HDRS = $(wildcard *.h)
+OBJS = $(patsubst %.c,%.o,$(wildcard libxc_*.c))
+
+LIBS = libxc.a libxc.so
+
+all: check-for-zlib $(LIBS)
+ ranlib libxc.a
+
+check-for-zlib:
+ @if [ ! -e /usr/include/zlib.h ]; then \
+ echo "***********************************************************"; \
+ echo "ERROR: install zlib header files (http://www.gzip.org/zlib)"; \
+ echo "***********************************************************"; \
+ false; \
+ fi
+
+install: all
+ mkdir -p ../../../install/lib
+ mkdir -p ../../../install/include
+ cp -a $(LIBS) ../../../install/lib
+ for i in $(LIBS) do ; chmod 755 ../../../install/bin/$i ; done
+ cp -a xc.h ../../../install/include
+ chmod 644 ../../../install/include/xc.h
+
+clean:
+ $(RM) *.a *.so *.o *.rpm $(LIBS)
+
+rpm: all
+ rm -rf staging
+ mkdir staging
+ mkdir staging/i386
+ rpmbuild --define "staging$$PWD/staging" --define '_builddir.' \
+ --define "_rpmdir$$PWD/staging" -bb rpm.spec
+ mv staging/i386/*.rpm .
+ rm -rf staging
+
+libxc.so: $(OBJS)
+ $(LD) -shared -o $@ $^ -lz
+
+libxc.a: libxc.a($(OBJS))
+
+%.o: %.c $(HDRS) Makefile
+ $(CC) $(CFLAGS) -o $@ $<
--- /dev/null
+/******************************************************************************
+ * libxc_bvtsched.c
+ *
+ * API for manipulating parameters of the Borrowed Virtual Time scheduler.
+ *
+ * Copyright (c) 2003, K A Fraser.
+ */
+
+#include "libxc_private.h"
+
+int xc_bvtsched_global_set(unsigned long ctx_allow)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_BVTCTL;
+ op.u.bvtctl.ctx_allow = ctx_allow;
+ return do_dom0_op(&op);
+}
+
+int xc_bvtsched_domain_set(unsigned int domid,
+ unsigned long mcuadv,
+ unsigned long warp,
+ unsigned long warpl,
+ unsigned long warpu)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_ADJUSTDOM;
+ op.u.adjustdom.domain = domid;
+ op.u.adjustdom.mcu_adv = mcuadv;
+ op.u.adjustdom.warp = warp;
+ op.u.adjustdom.warpl = warpl;
+ op.u.adjustdom.warpu = warpu;
+ return do_dom0_op(&op);
+}
--- /dev/null
+/******************************************************************************
+ * libxc_domain.c
+ *
+ * API for manipulating and obtaining information on domains.
+ *
+ * Copyright (c) 2003, K A Fraser.
+ */
+
+#include "libxc_private.h"
+
+int xc_domain_create(unsigned int mem_kb, const char *name)
+{
+ int err;
+ dom0_op_t op;
+
+ op.cmd = DOM0_CREATEDOMAIN;
+ op.u.createdomain.memory_kb = mem_kb;
+ strncpy(op.u.createdomain.name, name, MAX_DOMAIN_NAME);
+ op.u.createdomain.name[MAX_DOMAIN_NAME-1] = '\0';
+
+ err = do_dom0_op(&op);
+
+ return (err < 0) ? err : op.u.createdomain.domain;
+}
+
+
+int xc_domain_start(unsigned int domid)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_STARTDOMAIN;
+ op.u.startdomain.domain = domid;
+ return do_dom0_op(&op);
+}
+
+
+int xc_domain_stop(unsigned int domid)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_STOPDOMAIN;
+ op.u.stopdomain.domain = domid;
+ return do_dom0_op(&op);
+}
+
+
+int xc_domain_destroy(unsigned int domid, int force)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_DESTROYDOMAIN;
+ op.u.destroydomain.domain = domid;
+ op.u.destroydomain.force = !!force;
+ return do_dom0_op(&op);
+}
+
+int xc_domain_getinfo(unsigned int first_domid,
+ unsigned int max_doms,
+ xc_dominfo_t *info)
+{
+ unsigned int nr_doms, next_domid = first_domid;
+ dom0_op_t op;
+
+ for ( nr_doms = 0; nr_doms < max_doms; nr_doms++ )
+ {
+ op.cmd = DOM0_GETDOMAININFO;
+ op.u.getdomaininfo.domain = next_domid;
+ if ( do_dom0_op(&op) < 0 )
+ break;
+ info->domid = op.u.getdomaininfo.domain;
+ info->cpu = op.u.getdomaininfo.processor;
+ info->has_cpu = op.u.getdomaininfo.has_cpu;
+ info->stopped = (op.u.getdomaininfo.state == DOMSTATE_STOPPED);
+ info->nr_pages = op.u.getdomaininfo.tot_pages;
+ info->cpu_time = op.u.getdomaininfo.cpu_time;
+ strncpy(info->name, op.u.getdomaininfo.name, XC_DOMINFO_MAXNAME);
+ info->name[XC_DOMINFO_MAXNAME-1] = '\0';
+
+ next_domid = op.u.getdomaininfo.domain + 1;
+ }
+
+ return nr_doms;
+}
--- /dev/null
+/******************************************************************************
+ * libxc_linux_build.c
+ */
+
+#include "libxc_private.h"
+#include <zlib.h>
+
+/* This string is written to the head of every guest kernel image. */
+#define GUEST_SIG "XenoGues"
+#define SIG_LEN 8
+
+#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
+#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+
+static long get_tot_pages(int domid)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_GETDOMAININFO;
+ op.u.getdomaininfo.domain = domid;
+ return (do_dom0_op(&op) < 0) ? -1 : op.u.getdomaininfo.tot_pages;
+}
+
+static int get_pfn_list(
+ int domid, unsigned long *pfn_buf, unsigned long max_pfns)
+{
+ dom0_op_t op;
+ int ret;
+ op.cmd = DOM0_GETMEMLIST;
+ op.u.getmemlist.domain = domid;
+ op.u.getmemlist.max_pfns = max_pfns;
+ op.u.getmemlist.buffer = pfn_buf;
+
+ if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 )
+ return -1;
+
+ ret = do_dom0_op(&op);
+
+ (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long));
+
+ return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
+}
+
+static int send_pgupdates(mmu_update_t *updates, int nr_updates)
+{
+ int ret = -1;
+ privcmd_hypercall_t hypercall;
+
+ hypercall.op = __HYPERVISOR_mmu_update;
+ hypercall.arg[0] = (unsigned long)updates;
+ hypercall.arg[1] = (unsigned long)nr_updates;
+
+ if ( mlock(updates, nr_updates * sizeof(*updates)) != 0 )
+ goto out1;
+
+ if ( do_xen_hypercall(&hypercall) < 0 )
+ goto out2;
+
+ ret = 0;
+
+ out2: (void)munlock(updates, nr_updates * sizeof(*updates));
+ out1: return ret;
+}
+
+/* Read the kernel header, extracting the image size and load address. */
+static int read_kernel_header(gzFile gfd, long dom_size,
+ unsigned long *load_addr, int verbose)
+{
+ char signature[SIG_LEN];
+
+ gzread(gfd, signature, SIG_LEN);
+ if ( strncmp(signature, GUEST_SIG, SIG_LEN) )
+ {
+ if ( verbose )
+ ERROR("Kernel image does not contain required signature");
+ return -1;
+ }
+
+ /* Read the load address which immediately follows the Xeno signature. */
+ gzread(gfd, load_addr, sizeof(unsigned long));
+
+ return 0;
+}
+
+static int copy_to_domain_page(unsigned long dst_pfn, void *src_page)
+{
+ void *vaddr = map_pfn(dst_pfn);
+ if ( vaddr == NULL )
+ return -1;
+ memcpy(vaddr, src_page, PAGE_SIZE);
+ unmap_pfn(vaddr);
+ return 0;
+}
+
+static int setup_guestos(
+ int dom, gzFile kernel_gfd, int initrd_fd, unsigned long tot_pages,
+ unsigned long *virt_startinfo_addr, unsigned long virt_load_addr,
+ dom0_builddomain_t *builddomain, const char *cmdline,
+ unsigned long shared_info_frame, int verbose)
+{
+ l1_pgentry_t *vl1tab = NULL, *vl1e = NULL;
+ l2_pgentry_t *vl2tab = NULL, *vl2e = NULL;
+ unsigned long *page_array = NULL;
+ mmu_update_t *pgt_update_arr = NULL, *pgt_updates = NULL;
+ int alloc_index, num_pt_pages;
+ unsigned long l2tab;
+ unsigned long l1tab = 0;
+ unsigned long num_pgt_updates = 0;
+ unsigned long count, pt_start, i, j;
+ unsigned long initrd_addr = 0, initrd_len = 0;
+ start_info_t *start_info;
+ shared_info_t *shared_info;
+ unsigned long ksize;
+
+ memset(builddomain, 0, sizeof(*builddomain));
+
+ if ( init_pfn_mapper() < 0 )
+ goto error_out;
+
+ pgt_updates = malloc((tot_pages + 1024) * 3 * sizeof(mmu_update_t));
+ page_array = malloc(tot_pages * sizeof(unsigned long));
+ pgt_update_arr = pgt_updates;
+ if ( (pgt_update_arr == NULL) || (page_array == NULL) )
+ {
+ if ( verbose )
+ PERROR("Could not allocate memory");
+ goto error_out;
+ }
+
+ if ( get_pfn_list(dom, page_array, tot_pages) != tot_pages )
+ {
+ if ( verbose )
+ PERROR("Could not get the page frame list");
+ goto error_out;
+ }
+
+ /* Load the guest OS image. Let it take no more than 1/2 memory.*/
+ for ( i = 0; i < ((tot_pages/2)*PAGE_SIZE); i += PAGE_SIZE )
+ {
+ char page[PAGE_SIZE];
+ int size;
+ if ( (size = gzread(kernel_gfd, page, PAGE_SIZE)) == -1 )
+ {
+ if ( verbose )
+ PERROR("Error reading kernel image, could not"
+ " read the whole image.");
+ goto error_out;
+ }
+ if ( size == 0 )
+ goto kernel_copied;
+ copy_to_domain_page(page_array[i>>PAGE_SHIFT], page);
+ }
+ if ( verbose )
+ ERROR("Kernel too big to safely fit in domain memory");
+ goto error_out;
+
+ kernel_copied:
+ /* ksize is kernel-image size rounded up to a page boundary. */
+ ksize = i;
+
+ /* Load the initial ramdisk image. */
+ if ( initrd_fd >= 0 )
+ {
+ struct stat stat;
+ unsigned long isize;
+
+ if ( fstat(initrd_fd, &stat) < 0 )
+ {
+ if ( verbose )
+ PERROR("Could not stat the initrd image");
+ goto error_out;
+ }
+ isize = stat.st_size;
+ if ( (isize + ksize) > ((tot_pages/2) * PAGE_SIZE) )
+ {
+ if ( verbose )
+ ERROR("Kernel/initrd too big to safely fit in domain memory");
+ goto error_out;
+ }
+
+ initrd_addr = virt_load_addr + ksize;
+ initrd_len = isize;
+
+ for ( j = 0, i = ksize; j < isize; j += PAGE_SIZE, i += PAGE_SIZE )
+ {
+ char page[PAGE_SIZE];
+ int size = ((isize-j) < PAGE_SIZE) ? (isize-j) : PAGE_SIZE;
+ if ( read(initrd_fd, page, size) != size )
+ {
+ if ( verbose )
+ PERROR("Error reading initrd image, could not"
+ " read the whole image.");
+ goto error_out;
+ }
+ copy_to_domain_page(page_array[i>>PAGE_SHIFT], page);
+ }
+ }
+
+ alloc_index = tot_pages - 1;
+
+ /* Count bottom-level PTs, rounding up. */
+ num_pt_pages = (l1_table_offset(virt_load_addr) + tot_pages + 1023) / 1024;
+
+ /* We must also count the page directory. */
+ num_pt_pages++;
+
+ /* Index of first PT page. */
+ pt_start = tot_pages - num_pt_pages;
+
+ /*
+ * First allocate page for page dir. Allocation goes backwards from the end
+ * of the allocated physical address space.
+ */
+ l2tab = page_array[alloc_index] << PAGE_SHIFT;
+ alloc_index--;
+ builddomain->ctxt.pt_base = l2tab;
+
+ /*
+ * Pin down l2tab addr as page dir page - causes hypervisor to provide
+ * correct protection for the page
+ */
+ pgt_updates->ptr = l2tab | MMU_EXTENDED_COMMAND;
+ pgt_updates->val = MMUEXT_PIN_L2_TABLE;
+ pgt_updates++;
+ num_pgt_updates++;
+
+ /* Initialise the page tables. */
+ if ( (vl2tab = map_pfn(l2tab >> PAGE_SHIFT)) == NULL )
+ goto error_out;
+ memset(vl2tab, 0, PAGE_SIZE);
+ vl2e = vl2tab + l2_table_offset(virt_load_addr);
+ for ( count = 0; count < tot_pages; count++ )
+ {
+ if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 )
+ {
+ l1tab = page_array[alloc_index] << PAGE_SHIFT;
+ if ( (vl1tab = map_pfn(l1tab >> PAGE_SHIFT)) == NULL )
+ goto error_out;
+ memset(vl1tab, 0, PAGE_SIZE);
+ alloc_index--;
+
+ vl1e = vl1tab + l1_table_offset(virt_load_addr +
+ (count << PAGE_SHIFT));
+
+ /* make apropriate entry in the page directory */
+ pgt_updates->ptr = (unsigned long)vl2e;
+ pgt_updates->val = l1tab | L2_PROT;
+ pgt_updates++;
+ num_pgt_updates++;
+ vl2e++;
+ }
+
+ if ( count < pt_start )
+ {
+ pgt_updates->ptr = (unsigned long)vl1e;
+ pgt_updates->val = (page_array[count] << PAGE_SHIFT) | L1_PROT;
+ pgt_updates++;
+ num_pgt_updates++;
+ vl1e++;
+ }
+ else
+ {
+ pgt_updates->ptr = (unsigned long)vl1e;
+ pgt_updates->val =
+ ((page_array[count] << PAGE_SHIFT) | L1_PROT) & ~_PAGE_RW;
+ pgt_updates++;
+ num_pgt_updates++;
+ vl1e++;
+ }
+
+ pgt_updates->ptr =
+ (page_array[count] << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
+ pgt_updates->val = count;
+ pgt_updates++;
+ num_pgt_updates++;
+ }
+
+ *virt_startinfo_addr =
+ virt_load_addr + ((alloc_index-1) << PAGE_SHIFT);
+
+ start_info = map_pfn(page_array[alloc_index-1]);
+ memset(start_info, 0, sizeof(*start_info));
+ start_info->pt_base = virt_load_addr + ((tot_pages-1) << PAGE_SHIFT);
+ start_info->mod_start = initrd_addr;
+ start_info->mod_len = initrd_len;
+ start_info->nr_pages = tot_pages;
+ start_info->shared_info = shared_info_frame << PAGE_SHIFT;
+ start_info->dom_id = dom;
+ start_info->flags = 0;
+ strncpy(start_info->cmd_line, cmdline, MAX_CMD_LEN);
+ start_info->cmd_line[MAX_CMD_LEN-1] = '\0';
+
+ unmap_pfn(start_info);
+
+ /* shared_info page starts its life empty. */
+ shared_info = map_pfn(shared_info_frame);
+ memset(shared_info, 0, PAGE_SIZE);
+ unmap_pfn(shared_info);
+
+ /* Send the page update requests down to the hypervisor. */
+ if ( send_pgupdates(pgt_update_arr, num_pgt_updates) < 0 )
+ goto error_out;
+
+ free(page_array);
+ free(pgt_update_arr);
+ return 0;
+
+ error_out:
+ if ( page_array == NULL )
+ free(page_array);
+ if ( pgt_update_arr == NULL )
+ free(pgt_update_arr);
+ return -1;
+}
+
+int xc_domain_build(unsigned int domid,
+ const char *image_name,
+ const char *ramdisk_name,
+ const char *cmdline,
+ int verbose)
+{
+ dom0_op_t launch_op, op;
+ unsigned long load_addr;
+ long tot_pages;
+ int kernel_fd, initrd_fd = -1;
+ gzFile kernel_gfd;
+ int rc, i;
+ full_execution_context_t *ctxt;
+ unsigned long virt_startinfo_addr;
+
+ if ( (tot_pages = get_tot_pages(domid)) < 0 )
+ {
+ if ( verbose )
+ PERROR("Could not find total pages for domain");
+ return 1;
+ }
+
+ kernel_fd = open(image_name, O_RDONLY);
+ if ( kernel_fd < 0 )
+ {
+ if ( verbose )
+ PERROR("Could not open kernel image");
+ return 1;
+ }
+
+ if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL )
+ {
+ if ( verbose )
+ PERROR("Could not allocate decompression state for state file");
+ close(kernel_fd);
+ return 1;
+ }
+
+ rc = read_kernel_header(kernel_gfd,
+ tot_pages << (PAGE_SHIFT - 10),
+ &load_addr, verbose);
+ if ( rc < 0 )
+ goto error_out;
+
+ if ( (load_addr & (PAGE_SIZE-1)) != 0 )
+ {
+ if ( verbose )
+ ERROR("We can only deal with page-aligned load addresses");
+ goto error_out;
+ }
+
+ if ( (load_addr + (tot_pages << PAGE_SHIFT)) > HYPERVISOR_VIRT_START )
+ {
+ if ( verbose )
+ ERROR("Cannot map all domain memory without hitting Xen space");
+ goto error_out;
+ }
+
+ if ( ramdisk_name != NULL )
+ {
+ initrd_fd = open(ramdisk_name, O_RDONLY);
+ if ( initrd_fd < 0 )
+ {
+ if ( verbose )
+ PERROR("Could not open the initial ramdisk image");
+ goto error_out;
+ }
+ }
+
+ op.cmd = DOM0_GETDOMAININFO;
+ op.u.getdomaininfo.domain = domid;
+ if ( (do_dom0_op(&op) < 0) || (op.u.getdomaininfo.domain != domid) )
+ {
+ if ( verbose )
+ PERROR("Could not get info on domain");
+ goto error_out;
+ }
+ if ( (op.u.getdomaininfo.state != DOMSTATE_STOPPED) ||
+ (op.u.getdomaininfo.ctxt.pt_base != 0) )
+ {
+ if ( verbose )
+ ERROR("Domain is already constructed");
+ goto error_out;
+ }
+
+ if ( setup_guestos(domid, kernel_gfd, initrd_fd, tot_pages,
+ &virt_startinfo_addr,
+ load_addr, &launch_op.u.builddomain, cmdline,
+ op.u.getdomaininfo.shared_info_frame, verbose) < 0 )
+ {
+ if ( verbose )
+ ERROR("Error constructing guest OS");
+ goto error_out;
+ }
+
+ if ( initrd_fd >= 0 )
+ close(initrd_fd);
+ gzclose(kernel_gfd);
+
+ ctxt = &launch_op.u.builddomain.ctxt;
+
+ ctxt->flags = 0;
+
+ /*
+ * Initial register values:
+ * DS,ES,FS,GS = FLAT_RING1_DS
+ * CS:EIP = FLAT_RING1_CS:start_pc
+ * SS:ESP = FLAT_RING1_DS:start_stack
+ * ESI = start_info
+ * [EAX,EBX,ECX,EDX,EDI,EBP are zero]
+ * EFLAGS = IF | 2 (bit 1 is reserved and should always be 1)
+ */
+ ctxt->i386_ctxt.ds = FLAT_RING1_DS;
+ ctxt->i386_ctxt.es = FLAT_RING1_DS;
+ ctxt->i386_ctxt.fs = FLAT_RING1_DS;
+ ctxt->i386_ctxt.gs = FLAT_RING1_DS;
+ ctxt->i386_ctxt.ss = FLAT_RING1_DS;
+ ctxt->i386_ctxt.cs = FLAT_RING1_CS;
+ ctxt->i386_ctxt.eip = load_addr;
+ ctxt->i386_ctxt.esp = virt_startinfo_addr;
+ ctxt->i386_ctxt.esi = virt_startinfo_addr;
+ ctxt->i386_ctxt.eflags = (1<<9) | (1<<2);
+
+ /* FPU is set up to default initial state. */
+ memset(ctxt->i387_ctxt, 0, sizeof(ctxt->i387_ctxt));
+
+ /* Virtual IDT is empty at start-of-day. */
+ for ( i = 0; i < 256; i++ )
+ {
+ ctxt->trap_ctxt[i].vector = i;
+ ctxt->trap_ctxt[i].cs = FLAT_RING1_CS;
+ }
+ ctxt->fast_trap_idx = 0;
+
+ /* No LDT. */
+ ctxt->ldt_ents = 0;
+
+ /* Use the default Xen-provided GDT. */
+ ctxt->gdt_ents = 0;
+
+ /* Ring 1 stack is the initial stack. */
+ ctxt->ring1_ss = FLAT_RING1_DS;
+ ctxt->ring1_esp = virt_startinfo_addr;
+
+ /* No debugging. */
+ memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg));
+
+ /* No callback handlers. */
+ ctxt->event_callback_cs = FLAT_RING1_CS;
+ ctxt->event_callback_eip = 0;
+ ctxt->failsafe_callback_cs = FLAT_RING1_CS;
+ ctxt->failsafe_callback_eip = 0;
+
+ launch_op.u.builddomain.domain = domid;
+ launch_op.u.builddomain.num_vifs = 1;
+
+ launch_op.cmd = DOM0_BUILDDOMAIN;
+ rc = do_dom0_op(&launch_op);
+
+ return rc;
+
+ error_out:
+ if ( initrd_fd >= 0 )
+ close(initrd_fd);
+ gzclose(kernel_gfd);
+ return -1;
+}
--- /dev/null
+/******************************************************************************
+ * libxc_linux_restore.c
+ *
+ * Restore the state of a Xenolinux session.
+ *
+ * Copyright (c) 2003, K A Fraser.
+ */
+
+#include "libxc_private.h"
+#include <asm-xeno/suspend.h>
+#include <zlib.h>
+
+/* This may allow us to create a 'quiet' command-line option, if necessary. */
+#define verbose_printf(_f, _a...) \
+ do { \
+ if ( !verbose ) break; \
+ printf( _f , ## _a ); \
+ fflush(stdout); \
+ } while ( 0 )
+
+static int get_pfn_list(
+ int domain_id, unsigned long *pfn_buf, unsigned long max_pfns)
+{
+ dom0_op_t op;
+ int ret;
+ op.cmd = DOM0_GETMEMLIST;
+ op.u.getmemlist.domain = domain_id;
+ op.u.getmemlist.max_pfns = max_pfns;
+ op.u.getmemlist.buffer = pfn_buf;
+
+ if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 )
+ {
+ PERROR("Could not lock pfn list buffer");
+ return -1;
+ }
+
+ ret = do_dom0_op(&op);
+
+ (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long));
+
+ return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
+}
+
+#define MAX_MMU_UPDATES 1024
+
+static int flush_mmu_updates(mmu_update_t *mmu_updates,
+ int *mmu_update_idx)
+{
+ int err = 0;
+ privcmd_hypercall_t hypercall;
+
+ if ( *mmu_update_idx == 0 )
+ return 0;
+
+ hypercall.op = __HYPERVISOR_mmu_update;
+ hypercall.arg[0] = (unsigned long)mmu_updates;
+ hypercall.arg[1] = (unsigned long)*mmu_update_idx;
+
+ if ( mlock(mmu_updates, sizeof(mmu_updates)) != 0 )
+ {
+ PERROR("Could not lock pagetable update array");
+ err = 1;
+ goto out;
+ }
+
+ if ( do_xen_hypercall(&hypercall) < 0 )
+ {
+ ERROR("Failure when submitting mmu updates");
+ err = 1;
+ }
+
+ *mmu_update_idx = 0;
+
+ (void)munlock(mmu_updates, sizeof(mmu_updates));
+
+ out:
+ return err;
+}
+
+static int add_mmu_update(mmu_update_t *mmu_updates,
+ int *mmu_update_idx,
+ unsigned long ptr,
+ unsigned long val)
+{
+ mmu_updates[*mmu_update_idx].ptr = ptr;
+ mmu_updates[*mmu_update_idx].val = val;
+ if ( ++*mmu_update_idx == MAX_MMU_UPDATES )
+ return flush_mmu_updates(mmu_updates, mmu_update_idx);
+ return 0;
+}
+
+static int checked_read(gzFile fd, void *buf, size_t count)
+{
+ int rc;
+ while ( ((rc = gzread(fd, buf, count)) == -1) && (errno == EINTR) )
+ continue;
+ return rc == count;
+}
+
+int xc_linux_restore(const char *state_file, int verbose)
+{
+ dom0_op_t op;
+ int rc = 1, i, j;
+ unsigned long mfn, pfn, dom = 0;
+ unsigned int prev_pc, this_pc;
+
+ /* Number of page frames in use by this XenoLinux session. */
+ unsigned long nr_pfns;
+
+ /* The new domain's shared-info frame number. */
+ unsigned long shared_info_frame;
+ unsigned char shared_info[PAGE_SIZE]; /* saved contents from file */
+
+ /* A copy of the CPU context of the guest. */
+ full_execution_context_t ctxt;
+
+ /* First 16 bytes of the state file must contain 'XenoLinuxSuspend'. */
+ char signature[16];
+
+ /* A copy of the domain's name. */
+ char name[MAX_DOMAIN_NAME];
+
+ /* A table containg the type of each PFN (/not/ MFN!). */
+ unsigned long *pfn_type = NULL;
+
+ /* A temporary mapping, and a copy, of one frame of guest memory. */
+ unsigned long *ppage, page[1024];
+
+ /* A copy of the pfn-to-mfn table frame list. */
+ unsigned long pfn_to_mfn_frame_list[1024];
+
+ /* A table mapping each PFN to its new MFN. */
+ unsigned long *pfn_to_mfn_table = NULL;
+
+ /* A temporary mapping of the guest's suspend record. */
+ suspend_record_t *p_srec;
+
+ /* The name and descriptor of the file that we are reading from. */
+ int fd;
+ gzFile gfd;
+
+ mmu_update_t mmu_updates[MAX_MMU_UPDATES];
+ int mmu_update_idx = 0;
+
+ if ( (fd = open(state_file, O_RDONLY)) == -1 )
+ {
+ PERROR("Could not open state file for reading");
+ return 1;
+ }
+
+ if ( (gfd = gzdopen(fd, "rb")) == NULL )
+ {
+ ERROR("Could not allocate decompression state for state file");
+ close(fd);
+ return 1;
+ }
+
+ /* Start writing out the saved-domain record. */
+ if ( !checked_read(gfd, signature, 16) ||
+ (memcmp(signature, "XenoLinuxSuspend", 16) != 0) )
+ {
+ ERROR("Unrecognised state format -- no signature found");
+ goto out;
+ }
+
+ if ( !checked_read(gfd, name, sizeof(name)) ||
+ !checked_read(gfd, &nr_pfns, sizeof(unsigned long)) ||
+ !checked_read(gfd, &ctxt, sizeof(ctxt)) ||
+ !checked_read(gfd, shared_info, PAGE_SIZE) ||
+ !checked_read(gfd, pfn_to_mfn_frame_list, PAGE_SIZE) )
+ {
+ ERROR("Error when reading from state file");
+ goto out;
+ }
+
+ for ( i = 0; i < MAX_DOMAIN_NAME; i++ )
+ {
+ if ( name[i] == '\0' ) break;
+ if ( name[i] & 0x80 )
+ {
+ ERROR("Random characters in domain name");
+ goto out;
+ }
+ }
+ name[MAX_DOMAIN_NAME-1] = '\0';
+
+ if ( nr_pfns > 1024*1024 )
+ {
+ ERROR("Invalid state file -- pfn count out of range");
+ goto out;
+ }
+
+ /* We want zeroed memory so use calloc rather than malloc. */
+ pfn_to_mfn_table = calloc(1, 4 * nr_pfns);
+ pfn_type = calloc(1, 4 * nr_pfns);
+
+ if ( (pfn_to_mfn_table == NULL) || (pfn_type == NULL) )
+ {
+ errno = ENOMEM;
+ goto out;
+ }
+
+ if ( !checked_read(gfd, pfn_type, 4 * nr_pfns) )
+ {
+ ERROR("Error when reading from state file");
+ goto out;
+ }
+
+ /* Create a new domain of the appropriate size, and find it's dom_id. */
+ op.cmd = DOM0_CREATEDOMAIN;
+ op.u.createdomain.memory_kb = nr_pfns * (PAGE_SIZE / 1024);
+ memcpy(op.u.createdomain.name, name, MAX_DOMAIN_NAME);
+ if ( do_dom0_op(&op) < 0 )
+ {
+ ERROR("Could not create new domain");
+ goto out;
+ }
+ dom = op.u.createdomain.domain;
+
+ /* Get the domain's shared-info frame. */
+ op.cmd = DOM0_GETDOMAININFO;
+ op.u.getdomaininfo.domain = dom;
+ if ( do_dom0_op(&op) < 0 )
+ {
+ ERROR("Could not get information on new domain");
+ goto out;
+ }
+ shared_info_frame = op.u.getdomaininfo.shared_info_frame;
+
+ if ( init_pfn_mapper() < 0 )
+ goto out;
+
+ /* Copy saved contents of shared-info page. No checking needed. */
+ ppage = map_pfn(shared_info_frame);
+ memcpy(ppage, shared_info, PAGE_SIZE);
+ unmap_pfn(ppage);
+
+ /* Build the pfn-to-mfn table. We choose MFN ordering returned by Xen. */
+ if ( get_pfn_list(dom, pfn_to_mfn_table, nr_pfns) != nr_pfns )
+ {
+ ERROR("Did not read correct number of frame numbers for new dom");
+ goto out;
+ }
+
+ verbose_printf("Reloading memory pages: 0%%");
+
+ /*
+ * Now simply read each saved frame into its new machine frame.
+ * We uncanonicalise page tables as we go.
+ */
+ prev_pc = 0;
+ for ( i = 0; i < nr_pfns; i++ )
+ {
+ this_pc = (i * 100) / nr_pfns;
+ if ( (this_pc - prev_pc) >= 5 )
+ {
+ verbose_printf("\b\b\b\b%3d%%", this_pc);
+ prev_pc = this_pc;
+ }
+
+ mfn = pfn_to_mfn_table[i];
+
+ if ( !checked_read(gfd, page, PAGE_SIZE) )
+ {
+ ERROR("Error when reading from state file");
+ goto out;
+ }
+
+ ppage = map_pfn(mfn);
+ switch ( pfn_type[i] )
+ {
+ case L1TAB:
+ memset(ppage, 0, PAGE_SIZE);
+ if ( add_mmu_update(mmu_updates, &mmu_update_idx,
+ (mfn<<PAGE_SHIFT) | MMU_EXTENDED_COMMAND,
+ MMUEXT_PIN_L1_TABLE) )
+ goto out;
+ for ( j = 0; j < 1024; j++ )
+ {
+ if ( page[j] & _PAGE_PRESENT )
+ {
+ if ( (pfn = page[j] >> PAGE_SHIFT) >= nr_pfns )
+ {
+ ERROR("Frame number in page table is out of range");
+ goto out;
+ }
+ if ( (pfn_type[pfn] != NONE) && (page[j] & _PAGE_RW) )
+ {
+ ERROR("Write access requested for a restricted frame");
+ goto out;
+ }
+ page[j] &= (PAGE_SIZE - 1) & ~(_PAGE_GLOBAL | _PAGE_PAT);
+ page[j] |= pfn_to_mfn_table[pfn] << PAGE_SHIFT;
+ }
+ if ( add_mmu_update(mmu_updates, &mmu_update_idx,
+ (unsigned long)&ppage[j], page[j]) )
+ goto out;
+ }
+ break;
+ case L2TAB:
+ memset(ppage, 0, PAGE_SIZE);
+ if ( add_mmu_update(mmu_updates, &mmu_update_idx,
+ (mfn<<PAGE_SHIFT) | MMU_EXTENDED_COMMAND,
+ MMUEXT_PIN_L2_TABLE) )
+ goto out;
+ for ( j = 0; j < (HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT); j++ )
+ {
+ if ( page[j] & _PAGE_PRESENT )
+ {
+ if ( (pfn = page[j] >> PAGE_SHIFT) >= nr_pfns )
+ {
+ ERROR("Frame number in page table is out of range");
+ goto out;
+ }
+ if ( pfn_type[pfn] != L1TAB )
+ {
+ ERROR("Page table mistyping");
+ goto out;
+ }
+ /* Haven't reached the L1 table yet. Ensure it is safe! */
+ if ( pfn > i )
+ {
+ unsigned long **l1 = map_pfn(pfn_to_mfn_table[pfn]);
+ memset(l1, 0, PAGE_SIZE);
+ unmap_pfn(l1);
+ }
+ page[j] &= (PAGE_SIZE - 1) & ~(_PAGE_GLOBAL | _PAGE_PSE);
+ page[j] |= pfn_to_mfn_table[pfn] << PAGE_SHIFT;
+ }
+ if ( add_mmu_update(mmu_updates, &mmu_update_idx,
+ (unsigned long)&ppage[j], page[j]) )
+ goto out;
+ }
+ break;
+ default:
+ memcpy(ppage, page, PAGE_SIZE);
+ break;
+ }
+ /* NB. Must flush before unmapping page, as pass VAs to Xen. */
+ if ( flush_mmu_updates(mmu_updates, &mmu_update_idx) )
+ goto out;
+ unmap_pfn(ppage);
+
+ if ( add_mmu_update(mmu_updates, &mmu_update_idx,
+ (mfn<<PAGE_SHIFT) | MMU_MACHPHYS_UPDATE, i) )
+ goto out;
+ }
+
+ if ( flush_mmu_updates(mmu_updates, &mmu_update_idx) )
+ goto out;
+
+ verbose_printf("\b\b\b\b100%%\nMemory reloaded.\n");
+
+ /* Uncanonicalise the suspend-record frame number and poke resume rec. */
+ pfn = ctxt.i386_ctxt.esi;
+ if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NONE) )
+ {
+ ERROR("Suspend record frame number is bad");
+ goto out;
+ }
+ ctxt.i386_ctxt.esi = mfn = pfn_to_mfn_table[pfn];
+ p_srec = map_pfn(mfn);
+ p_srec->resume_info.nr_pages = nr_pfns;
+ p_srec->resume_info.shared_info = shared_info_frame << PAGE_SHIFT;
+ p_srec->resume_info.dom_id = dom;
+ p_srec->resume_info.flags = 0;
+ unmap_pfn(p_srec);
+
+ /* Uncanonicalise each GDT frame number. */
+ if ( ctxt.gdt_ents > 8192 )
+ {
+ ERROR("GDT entry count out of range");
+ goto out;
+ }
+ for ( i = 0; i < ctxt.gdt_ents; i += 512 )
+ {
+ pfn = ctxt.gdt_frames[i];
+ if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NONE) )
+ {
+ ERROR("GDT frame number is bad");
+ goto out;
+ }
+ ctxt.gdt_frames[i] = pfn_to_mfn_table[pfn];
+ }
+
+ /* Uncanonicalise the page table base pointer. */
+ pfn = ctxt.pt_base >> PAGE_SHIFT;
+ if ( (pfn >= nr_pfns) || (pfn_type[pfn] != L2TAB) )
+ {
+ ERROR("PT base is bad");
+ goto out;
+ }
+ ctxt.pt_base = pfn_to_mfn_table[pfn] << PAGE_SHIFT;
+
+ /* Uncanonicalise the pfn-to-mfn table frame-number list. */
+ for ( i = 0; i < nr_pfns; i += 1024 )
+ {
+ unsigned long copy_size = (nr_pfns - i) * sizeof(unsigned long);
+ if ( copy_size > PAGE_SIZE ) copy_size = PAGE_SIZE;
+ pfn = pfn_to_mfn_frame_list[i/1024];
+ if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NONE) )
+ {
+ ERROR("PFN-to-MFN frame number is bad");
+ goto out;
+ }
+ ppage = map_pfn(pfn_to_mfn_table[pfn]);
+ memcpy(ppage, &pfn_to_mfn_table[i], copy_size);
+ unmap_pfn(ppage);
+ }
+
+ /*
+ * Safety checking of saved context:
+ * 1. i386_ctxt is fine, as Xen checks that on context switch.
+ * 2. i387_ctxt is fine, as it can't hurt Xen.
+ * 3. trap_ctxt needs the code selectors checked.
+ * 4. fast_trap_idx is checked by Xen.
+ * 5. ldt base must be page-aligned, no more than 8192 ents, ...
+ * 6. gdt already done, and further checking is done by Xen.
+ * 7. check that ring1_ss is safe.
+ * 8. pt_base is already done.
+ * 9. debugregs are checked by Xen.
+ * 10. callback code selectors need checking.
+ */
+ for ( i = 0; i < 256; i++ )
+ {
+ ctxt.trap_ctxt[i].vector = i;
+ if ( (ctxt.trap_ctxt[i].cs & 3) == 0 )
+ ctxt.trap_ctxt[i].cs = FLAT_RING1_CS;
+ }
+ if ( (ctxt.ring1_ss & 3) == 0 )
+ ctxt.ring1_ss = FLAT_RING1_DS;
+ if ( (ctxt.event_callback_cs & 3) == 0 )
+ ctxt.event_callback_cs = FLAT_RING1_CS;
+ if ( (ctxt.failsafe_callback_cs & 3) == 0 )
+ ctxt.failsafe_callback_cs = FLAT_RING1_CS;
+ if ( ((ctxt.ldt_base & (PAGE_SIZE - 1)) != 0) ||
+ (ctxt.ldt_ents > 8192) ||
+ (ctxt.ldt_base > HYPERVISOR_VIRT_START) ||
+ ((ctxt.ldt_base + ctxt.ldt_ents*8) > HYPERVISOR_VIRT_START) )
+ {
+ ERROR("Bad LDT base or size");
+ goto out;
+ }
+
+ op.cmd = DOM0_BUILDDOMAIN;
+ op.u.builddomain.domain = dom;
+ op.u.builddomain.num_vifs = 1;
+ memcpy(&op.u.builddomain.ctxt, &ctxt, sizeof(ctxt));
+ rc = do_dom0_op(&op);
+
+ out:
+ if ( rc != 0 )
+ {
+ if ( dom != 0 )
+ {
+ op.cmd = DOM0_DESTROYDOMAIN;
+ op.u.destroydomain.domain = dom;
+ op.u.destroydomain.force = 1;
+ (void)do_dom0_op(&op);
+ }
+ }
+ else
+ {
+ /* Success: print the domain id. */
+ verbose_printf("DOM=%ld\n", dom);
+ }
+
+ if ( pfn_to_mfn_table != NULL )
+ free(pfn_to_mfn_table);
+ if ( pfn_type != NULL )
+ free(pfn_type);
+
+ gzclose(gfd);
+
+ return (rc == 0) ? dom : rc;
+}
--- /dev/null
+/******************************************************************************
+ * libxc_linux_save.c
+ *
+ * Save the state of a running Xenolinux session.
+ *
+ * Copyright (c) 2003, K A Fraser.
+ */
+
+#include "libxc_private.h"
+#include <asm-xeno/suspend.h>
+#include <zlib.h>
+
+/* This may allow us to create a 'quiet' command-line option, if necessary. */
+#define verbose_printf(_f, _a...) \
+ do { \
+ if ( !verbose ) break; \
+ printf( _f , ## _a ); \
+ fflush(stdout); \
+ } while ( 0 )
+
+/*
+ * Returns TRUE if the given machine frame number has a unique mapping
+ * in the guest's pseudophysical map.
+ */
+#define MFN_IS_IN_PSEUDOPHYS_MAP(_mfn) \
+ (((_mfn) < (1024*1024)) && \
+ (pfn_to_mfn_table[mfn_to_pfn_table[_mfn]] == (_mfn)))
+
+/* Returns TRUE if MFN is successfully converted to a PFN. */
+#define translate_mfn_to_pfn(_pmfn) \
+({ \
+ unsigned long mfn = *(_pmfn); \
+ int _res = 1; \
+ if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) ) \
+ _res = 0; \
+ else \
+ *(_pmfn) = mfn_to_pfn_table[mfn]; \
+ _res; \
+})
+
+static int check_pfn_ownership(unsigned long mfn, unsigned int dom)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_GETPAGEFRAMEINFO;
+ op.u.getpageframeinfo.pfn = mfn;
+ if ( (do_dom0_op(&op) < 0) || (op.u.getpageframeinfo.domain != dom) )
+ return 0;
+ return 1;
+}
+
+#define GETPFN_ERR (~0U)
+static unsigned int get_pfn_type(unsigned long mfn)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_GETPAGEFRAMEINFO;
+ op.u.getpageframeinfo.pfn = mfn;
+ if ( do_dom0_op(&op) < 0 )
+ {
+ PERROR("Unexpected failure when getting page frame info!");
+ return GETPFN_ERR;
+ }
+ return op.u.getpageframeinfo.type;
+}
+
+static int checked_write(gzFile fd, void *buf, size_t count)
+{
+ int rc;
+ while ( ((rc = gzwrite(fd, buf, count)) == -1) && (errno = EINTR) )
+ continue;
+ return rc == count;
+}
+
+int xc_linux_save(unsigned int domid, const char *state_file, int verbose)
+{
+ dom0_op_t op;
+ int rc = 1, i, j;
+ unsigned long mfn;
+ unsigned int prev_pc, this_pc;
+
+ /* Remember if we stopped the guest, so we can restart it on exit. */
+ int we_stopped_it = 0;
+
+ /* The new domain's shared-info frame number. */
+ unsigned long shared_info_frame;
+
+ /* A copy of the CPU context of the guest. */
+ full_execution_context_t ctxt;
+
+ /* A copy of the domain's name. */
+ char name[MAX_DOMAIN_NAME];
+
+ /* A table containg the type of each PFN (/not/ MFN!). */
+ unsigned long *pfn_type = NULL;
+
+ /* A temporary mapping, and a copy, of one frame of guest memory. */
+ unsigned long *ppage, page[1024];
+
+ /* A temporary mapping, and a copy, of the pfn-to-mfn table frame list. */
+ unsigned long *p_pfn_to_mfn_frame_list, pfn_to_mfn_frame_list[1024];
+ /* A temporary mapping of one frame in the above list. */
+ unsigned long *pfn_to_mfn_frame;
+
+ /* A table mapping each PFN to its current MFN. */
+ unsigned long *pfn_to_mfn_table = NULL;
+ /* A table mapping each current MFN to its canonical PFN. */
+ unsigned long *mfn_to_pfn_table = NULL;
+
+ /* A temporary mapping, and a copy, of the guest's suspend record. */
+ suspend_record_t *p_srec, srec;
+
+ /* The name and descriptor of the file that we are writing to. */
+ int fd;
+ gzFile gfd;
+
+ if ( (fd = open(state_file, O_CREAT|O_EXCL|O_WRONLY, 0644)) == -1 )
+ {
+ PERROR("Could not open file for writing");
+ return 1;
+ }
+
+ /*
+ * Compression rate 1: we want speed over compression. We're mainly going
+ * for those zero pages, after all.
+ */
+ if ( (gfd = gzdopen(fd, "wb1")) == NULL )
+ {
+ ERROR("Could not allocate compression state for state file");
+ close(fd);
+ return 1;
+ }
+
+ /* Ensure that the domain exists, and that it is stopped. */
+ for ( ; ; )
+ {
+ op.cmd = DOM0_GETDOMAININFO;
+ op.u.getdomaininfo.domain = domid;
+ if ( (do_dom0_op(&op) < 0) || (op.u.getdomaininfo.domain != domid) )
+ {
+ PERROR("Could not get info on domain");
+ goto out;
+ }
+
+ memcpy(&ctxt, &op.u.getdomaininfo.ctxt, sizeof(ctxt));
+ memcpy(name, op.u.getdomaininfo.name, sizeof(name));
+ shared_info_frame = op.u.getdomaininfo.shared_info_frame;
+
+ if ( op.u.getdomaininfo.state == DOMSTATE_STOPPED )
+ break;
+
+ we_stopped_it = 1;
+
+ op.cmd = DOM0_STOPDOMAIN;
+ op.u.stopdomain.domain = domid;
+ (void)do_dom0_op(&op);
+
+ sleep(1);
+ }
+
+ /* A cheesy test to see whether the domain contains valid state. */
+ if ( ctxt.pt_base == 0 )
+ {
+ ERROR("Domain is not in a valid Xenolinux state");
+ goto out;
+ }
+
+ if ( init_pfn_mapper() < 0 )
+ goto out;
+
+ /* Is the suspend-record MFN actually valid for this domain? */
+ if ( !check_pfn_ownership(ctxt.i386_ctxt.esi, domid) )
+ {
+ ERROR("Invalid state record pointer");
+ goto out;
+ }
+
+ /* If the suspend-record MFN is okay then grab a copy of it to @srec. */
+ p_srec = map_pfn(ctxt.i386_ctxt.esi);
+ memcpy(&srec, p_srec, sizeof(srec));
+ unmap_pfn(p_srec);
+
+ if ( srec.nr_pfns > 1024*1024 )
+ {
+ ERROR("Invalid state record -- pfn count out of range");
+ goto out;
+ }
+
+ if ( !check_pfn_ownership(srec.pfn_to_mfn_frame_list, domid) )
+ {
+ ERROR("Invalid pfn-to-mfn frame list pointer");
+ goto out;
+ }
+
+ /* Grab a copy of the pfn-to-mfn table frame list. */
+ p_pfn_to_mfn_frame_list = map_pfn(srec.pfn_to_mfn_frame_list);
+ memcpy(pfn_to_mfn_frame_list, p_pfn_to_mfn_frame_list, PAGE_SIZE);
+ unmap_pfn(p_pfn_to_mfn_frame_list);
+
+ /* We want zeroed memory so use calloc rather than malloc. */
+ mfn_to_pfn_table = calloc(1, 4 * 1024 * 1024);
+ pfn_to_mfn_table = calloc(1, 4 * srec.nr_pfns);
+ pfn_type = calloc(1, 4 * srec.nr_pfns);
+
+ if ( (mfn_to_pfn_table == NULL) ||
+ (pfn_to_mfn_table == NULL) ||
+ (pfn_type == NULL) )
+ {
+ errno = ENOMEM;
+ goto out;
+ }
+
+
+ /*
+ * Construct the local pfn-to-mfn and mfn-to-pfn tables. On exit from this
+ * loop we have each MFN mapped at most once. Note that there may be MFNs
+ * that aren't mapped at all: we detect these by MFN_IS_IN_PSEUDOPHYS_MAP.
+ */
+ pfn_to_mfn_frame = NULL;
+ for ( i = 0; i < srec.nr_pfns; i++ )
+ {
+ /* Each frameful of table frames must be checked & mapped on demand. */
+ if ( (i & 1023) == 0 )
+ {
+ mfn = pfn_to_mfn_frame_list[i/1024];
+ if ( !check_pfn_ownership(mfn, domid) )
+ {
+ ERROR("Invalid frame number if pfn-to-mfn frame list");
+ goto out;
+ }
+ if ( pfn_to_mfn_frame != NULL )
+ unmap_pfn(pfn_to_mfn_frame);
+ pfn_to_mfn_frame = map_pfn(mfn);
+ }
+
+ mfn = pfn_to_mfn_frame[i & 1023];
+
+ if ( !check_pfn_ownership(mfn, domid) )
+ {
+ ERROR("Invalid frame specified with pfn-to-mfn table");
+ goto out;
+ }
+
+ /* Did we map this MFN already? That would be invalid! */
+ if ( MFN_IS_IN_PSEUDOPHYS_MAP(mfn) )
+ {
+ ERROR("A machine frame appears twice in pseudophys space");
+ goto out;
+ }
+
+ pfn_to_mfn_table[i] = mfn;
+ mfn_to_pfn_table[mfn] = i;
+
+ /* Query page type by MFN, but store it by PFN. */
+ if ( (pfn_type[i] = get_pfn_type(mfn)) == GETPFN_ERR )
+ goto out;
+ }
+
+ /* Canonicalise the suspend-record frame number. */
+ if ( !translate_mfn_to_pfn(&ctxt.i386_ctxt.esi) )
+ {
+ ERROR("State record is not in range of pseudophys map");
+ goto out;
+ }
+
+ /* Canonicalise each GDT frame number. */
+ for ( i = 0; i < ctxt.gdt_ents; i += 512 )
+ {
+ if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[i]) )
+ {
+ ERROR("GDT frame is not in range of pseudophys map");
+ goto out;
+ }
+ }
+
+ /* Canonicalise the page table base pointer. */
+ if ( !MFN_IS_IN_PSEUDOPHYS_MAP(ctxt.pt_base >> PAGE_SHIFT) )
+ {
+ ERROR("PT base is not in range of pseudophys map");
+ goto out;
+ }
+ ctxt.pt_base = mfn_to_pfn_table[ctxt.pt_base >> PAGE_SHIFT] << PAGE_SHIFT;
+
+ /* Canonicalise the pfn-to-mfn table frame-number list. */
+ for ( i = 0; i < srec.nr_pfns; i += 1024 )
+ {
+ if ( !translate_mfn_to_pfn(&pfn_to_mfn_frame_list[i/1024]) )
+ {
+ ERROR("Frame # in pfn-to-mfn frame list is not in pseudophys");
+ goto out;
+ }
+ }
+
+ /* Start writing out the saved-domain record. */
+ ppage = map_pfn(shared_info_frame);
+ if ( !checked_write(gfd, "XenoLinuxSuspend", 16) ||
+ !checked_write(gfd, name, sizeof(name)) ||
+ !checked_write(gfd, &srec.nr_pfns, sizeof(unsigned long)) ||
+ !checked_write(gfd, &ctxt, sizeof(ctxt)) ||
+ !checked_write(gfd, ppage, PAGE_SIZE) ||
+ !checked_write(gfd, pfn_to_mfn_frame_list, PAGE_SIZE) ||
+ !checked_write(gfd, pfn_type, 4 * srec.nr_pfns) )
+ {
+ ERROR("Error when writing to state file");
+ goto out;
+ }
+ unmap_pfn(ppage);
+
+ verbose_printf("Saving memory pages: 0%%");
+
+ /* Now write out each data page, canonicalising page tables as we go... */
+ prev_pc = 0;
+ for ( i = 0; i < srec.nr_pfns; i++ )
+ {
+ this_pc = (i * 100) / srec.nr_pfns;
+ if ( (this_pc - prev_pc) >= 5 )
+ {
+ verbose_printf("\b\b\b\b%3d%%", this_pc);
+ prev_pc = this_pc;
+ }
+
+ mfn = pfn_to_mfn_table[i];
+
+ ppage = map_pfn(mfn);
+ memcpy(page, ppage, PAGE_SIZE);
+ unmap_pfn(ppage);
+
+ if ( (pfn_type[i] == L1TAB) || (pfn_type[i] == L2TAB) )
+ {
+ for ( j = 0;
+ j < ((pfn_type[i] == L2TAB) ?
+ (HYPERVISOR_VIRT_START >> L2_PAGETABLE_SHIFT) : 1024);
+ j++ )
+ {
+ if ( !(page[j] & _PAGE_PRESENT) ) continue;
+ mfn = page[j] >> PAGE_SHIFT;
+ if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) )
+ {
+ ERROR("Frame number in pagetable page is invalid");
+ goto out;
+ }
+ page[j] &= PAGE_SIZE - 1;
+ page[j] |= mfn_to_pfn_table[mfn] << PAGE_SHIFT;
+ }
+ }
+
+ if ( !checked_write(gfd, page, PAGE_SIZE) )
+ {
+ ERROR("Error when writing to state file");
+ goto out;
+ }
+ }
+
+ verbose_printf("\b\b\b\b100%%\nMemory saved.\n");
+
+ /* Success! */
+ rc = 0;
+
+ out:
+ /* Restart the domain if we had to stop it to save its state. */
+ if ( we_stopped_it )
+ {
+ op.cmd = DOM0_STARTDOMAIN;
+ op.u.startdomain.domain = domid;
+ (void)do_dom0_op(&op);
+ }
+
+ gzclose(gfd);
+
+ if ( pfn_to_mfn_table != NULL )
+ free(pfn_to_mfn_table);
+ if ( mfn_to_pfn_table != NULL )
+ free(mfn_to_pfn_table);
+ if ( pfn_type != NULL )
+ free(pfn_type);
+
+ /* On error, make sure the file is deleted. */
+ if ( rc != 0 )
+ unlink(state_file);
+
+ return !!rc;
+}
--- /dev/null
+/******************************************************************************
+ * libxc_misc.c
+ *
+ * Miscellaneous control interface functions.
+ */
+
+#include "libxc_private.h"
+
+int privcmd_fd = -1;
+
+int xc_interface_open(void)
+{
+ if ( (privcmd_fd == -1) &&
+ ((privcmd_fd = open("/proc/xeno/privcmd", O_RDWR)) < 0) )
+ {
+ privcmd_fd = -1;
+ return -1;
+ }
+ return 0;
+}
+
+int xc_interface_close(void)
+{
+ if ( privcmd_fd != -1 )
+ {
+ close(privcmd_fd);
+ privcmd_fd = -1;
+ }
+ return 0;
+}
+
+
+#define CONSOLE_RING_CLEAR 1
+
+int xc_readconsolering(char *str, unsigned int max_chars, int clear)
+{
+ int ret;
+ dom0_op_t op;
+
+ op.cmd = DOM0_READCONSOLE;
+ op.u.readconsole.str = (unsigned long)str;
+ op.u.readconsole.count = max_chars;
+ op.u.readconsole.cmd = clear ? CONSOLE_RING_CLEAR : 0;
+
+ if ( (ret = do_dom0_op(&op)) > 0 )
+ str[ret] = '\0';
+
+ return ret;
+}
+
--- /dev/null
+/******************************************************************************
+ * libxc_private.c
+ *
+ * Helper functions for the rest of the library.
+ */
+
+#include "libxc_private.h"
+
+static int devmem_fd = -1;
+
+int init_pfn_mapper(void)
+{
+ if ( (devmem_fd == -1) &&
+ ((devmem_fd = open("/dev/mem", O_RDWR)) < 0) )
+ {
+ devmem_fd = -1;
+ return -1;
+ }
+ return 0;
+}
+
+void *map_pfn(unsigned long pfn)
+{
+ void *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE,
+ MAP_SHARED, devmem_fd, pfn << PAGE_SHIFT);
+ if ( vaddr == MAP_FAILED )
+ return NULL;
+ return vaddr;
+}
+
+void unmap_pfn(void *vaddr)
+{
+ (void)munmap(vaddr, PAGE_SIZE);
+}
--- /dev/null
+
+#ifndef __LIBXC_PRIVATE_H__
+#define __LIBXC_PRIVATE_H__
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+typedef unsigned long long u64;
+typedef signed char s8;
+typedef signed short s16;
+typedef signed long s32;
+typedef signed long long s64;
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <string.h>
+
+#include "xc.h"
+
+#include <asm-xeno/proc_cmd.h>
+#include <hypervisor-ifs/hypervisor-if.h>
+#include <hypervisor-ifs/dom0_ops.h>
+#include <hypervisor-ifs/vbd.h>
+
+#define _PAGE_PRESENT 0x001
+#define _PAGE_RW 0x002
+#define _PAGE_USER 0x004
+#define _PAGE_PWT 0x008
+#define _PAGE_PCD 0x010
+#define _PAGE_ACCESSED 0x020
+#define _PAGE_DIRTY 0x040
+#define _PAGE_PAT 0x080
+#define _PAGE_PSE 0x080
+#define _PAGE_GLOBAL 0x100
+
+
+#define L1_PAGETABLE_SHIFT 12
+#define L2_PAGETABLE_SHIFT 22
+
+#define ENTRIES_PER_L1_PAGETABLE 1024
+#define ENTRIES_PER_L2_PAGETABLE 1024
+
+#define PAGE_SHIFT L1_PAGETABLE_SHIFT
+#define PAGE_SIZE (1UL << PAGE_SHIFT)
+#define PAGE_MASK (~(PAGE_SIZE-1))
+
+typedef struct { unsigned long l1_lo; } l1_pgentry_t;
+typedef struct { unsigned long l2_lo; } l2_pgentry_t;
+
+#define l1_table_offset(_a) \
+ (((_a) >> L1_PAGETABLE_SHIFT) & (ENTRIES_PER_L1_PAGETABLE - 1))
+#define l2_table_offset(_a) \
+ ((_a) >> L2_PAGETABLE_SHIFT)
+
+#define ERROR(_m) \
+ fprintf(stderr, "ERROR: %s\n", (_m))
+
+#define PERROR(_m) \
+ fprintf(stderr, "ERROR: %s (%d = %s)\n", (_m), errno, strerror(errno))
+
+extern int privcmd_fd;
+static inline int do_privcmd(unsigned int cmd, unsigned long data)
+{
+ return ioctl(privcmd_fd, cmd, data);
+}
+
+static inline int do_xen_hypercall(privcmd_hypercall_t *hypercall)
+{
+ return do_privcmd(IOCTL_PRIVCMD_HYPERCALL, (unsigned long)hypercall);
+}
+
+static inline int do_dom0_op(dom0_op_t *op)
+{
+ int ret = -1;
+ privcmd_hypercall_t hypercall;
+
+ op->interface_version = DOM0_INTERFACE_VERSION;
+
+ hypercall.op = __HYPERVISOR_dom0_op;
+ hypercall.arg[0] = (unsigned long)op;
+
+ if ( mlock(op, sizeof(*op)) != 0 )
+ goto out1;
+
+ if ( (ret = do_xen_hypercall(&hypercall)) < 0 )
+ {
+ if ( errno == EACCES )
+ fprintf(stderr, "Dom0 operation failed -- need to"
+ " rebuild the user-space tool set?\n");
+ goto out2;
+ }
+
+ ret = 0;
+
+ out2: (void)munlock(op, sizeof(*op));
+ out1: return ret;
+}
+
+static inline int do_network_op(network_op_t *op)
+{
+ int ret = -1;
+ privcmd_hypercall_t hypercall;
+
+ hypercall.op = __HYPERVISOR_network_op;
+ hypercall.arg[0] = (unsigned long)op;
+
+ if ( mlock(op, sizeof(*op)) != 0 )
+ goto out1;
+
+ if ( (ret = do_xen_hypercall(&hypercall)) < 0 )
+ goto out2;
+
+ ret = 0;
+
+ out2: (void)munlock(op, sizeof(*op));
+ out1: return ret;
+}
+
+
+static inline int do_block_io_op(block_io_op_t *op)
+{
+ int ret = -1;
+ privcmd_hypercall_t hypercall;
+
+ hypercall.op = __HYPERVISOR_block_io_op;
+ hypercall.arg[0] = (unsigned long)op;
+
+ if ( mlock(op, sizeof(*op)) != 0 )
+ goto out1;
+
+ if ( do_xen_hypercall(&hypercall) < 0 )
+ goto out2;
+
+ ret = 0;
+
+ out2: (void)munlock(op, sizeof(*op));
+ out1: return ret;
+}
+
+/*
+ * PFN mapping.
+ */
+int init_pfn_mapper(void);
+void *map_pfn(unsigned long pfn);
+void unmap_pfn(void *vaddr);
+
+#endif /* __LIBXC_PRIVATE_H__ */
--- /dev/null
+/******************************************************************************
+ * libxc_vbd.c
+ *
+ * API for manipulating and accessing per-domain virtual block devices.
+ *
+ * Copyright (c) 2003, K A Fraser.
+ */
+
+#define _GNU_SOURCE
+#include "libxc_private.h"
+
+int xc_vbd_create(unsigned int domid, unsigned short vbdid, int writeable)
+{
+ block_io_op_t op;
+ op.cmd = BLOCK_IO_OP_VBD_CREATE;
+ op.u.create_params.domain = domid;
+ op.u.create_params.vdevice = vbdid;
+ op.u.create_params.mode = VBD_MODE_R | (writeable ? VBD_MODE_W : 0);
+ return do_block_io_op(&op);
+}
+
+
+int xc_vbd_destroy(unsigned int domid, unsigned short vbdid)
+{
+ block_io_op_t op;
+ op.cmd = BLOCK_IO_OP_VBD_DELETE;
+ op.u.delete_params.domain = domid;
+ op.u.delete_params.vdevice = vbdid;
+ return do_block_io_op(&op);
+}
+
+
+int xc_vbd_add_extent(unsigned int domid,
+ unsigned short vbdid,
+ unsigned short real_device,
+ unsigned long start_sector,
+ unsigned long nr_sectors)
+{
+ block_io_op_t op;
+ op.cmd = BLOCK_IO_OP_VBD_ADD;
+ op.u.add_params.domain = domid;
+ op.u.add_params.vdevice = vbdid;
+ op.u.add_params.extent.device = real_device;
+ op.u.add_params.extent.start_sector = start_sector;
+ op.u.add_params.extent.nr_sectors = nr_sectors;
+ return do_block_io_op(&op);
+}
+
+
+int xc_vbd_delete_extent(unsigned int domid,
+ unsigned short vbdid,
+ unsigned short real_device,
+ unsigned long start_sector,
+ unsigned long nr_sectors)
+{
+ block_io_op_t op;
+ op.cmd = BLOCK_IO_OP_VBD_REMOVE;
+ op.u.add_params.domain = domid;
+ op.u.add_params.vdevice = vbdid;
+ op.u.add_params.extent.device = real_device;
+ op.u.add_params.extent.start_sector = start_sector;
+ op.u.add_params.extent.nr_sectors = nr_sectors;
+ return do_block_io_op(&op);
+}
+
+
+int xc_vbd_probe(unsigned int domid,
+ unsigned short vbdid,
+ unsigned int max_vbds,
+ xc_vbd_t *vbds)
+{
+ block_io_op_t op;
+ xen_disk_info_t *xdi = &op.u.probe_params.xdi;
+ int i, j, ret, allocsz = max_vbds * sizeof(xen_disk_t);
+
+ op.cmd = BLOCK_IO_OP_VBD_PROBE;
+ op.u.probe_params.domain = domid;
+
+ xdi->max = max_vbds;
+ xdi->disks = malloc(allocsz);
+ xdi->count = 0;
+
+ if ( (xdi->disks == NULL) || (mlock(xdi->disks, allocsz) != 0) )
+ {
+ if ( xdi->disks != NULL )
+ free(xdi->disks);
+ return -ENOMEM;
+ }
+
+ ret = do_block_io_op(&op);
+
+ (void)munlock(xdi->disks, allocsz);
+
+ if ( ret >= 0 )
+ {
+ for ( i = 0, j = 0; i < xdi->count; i++ )
+ {
+ if ( !(xdi->disks[i].info & XD_FLAG_VIRT) )
+ continue;
+
+ vbds[j].domid = xdi->disks[i].domain;
+ vbds[j].vbdid = xdi->disks[i].device;
+ vbds[j].flags = (xdi->disks[i].info & XD_FLAG_RO) ?
+ 0 : XC_VBDF_WRITEABLE;
+ vbds[j].nr_sectors = xdi->disks[i].capacity;
+
+ j++;
+ }
+
+ ret = j;
+ }
+
+ free(xdi->disks);
+
+ return ret;
+}
--- /dev/null
+/******************************************************************************
+ * libxc_vif.c
+ *
+ * API for manipulating and accessing per-network-interface parameters.
+ *
+ * Copyright (c) 2003, K A Fraser.
+ */
+
+#include "libxc_private.h"
+
+int xc_vif_scheduler_set(unsigned int domid,
+ unsigned int vifid,
+ xc_vif_sched_params_t *params)
+{
+ network_op_t netop;
+ netop.cmd = NETWORK_OP_VIFSETPARAMS;
+ netop.u.vif_setparams.domain = domid;
+ netop.u.vif_setparams.vif = vifid;
+ netop.u.vif_setparams.credit_bytes = params->credit_bytes;
+ netop.u.vif_setparams.credit_usec = params->credit_usec;
+ return do_network_op(&netop);
+}
+
+
+int xc_vif_scheduler_get(unsigned int domid,
+ unsigned int vifid,
+ xc_vif_sched_params_t *params)
+{
+ network_op_t netop;
+ int rc;
+
+ netop.cmd = NETWORK_OP_VIFGETINFO;
+ netop.u.vif_getinfo.domain = domid;
+ netop.u.vif_getinfo.vif = vifid;
+
+ if ( (rc = do_network_op(&netop)) >= 0 )
+ {
+ params->credit_bytes = netop.u.vif_getinfo.credit_bytes;
+ params->credit_usec = netop.u.vif_getinfo.credit_usec;
+ }
+
+ return rc;
+}
+
+
+int xc_vif_stats_get(unsigned int domid,
+ unsigned int vifid,
+ xc_vif_stats_t *stats)
+{
+ network_op_t netop;
+ int rc;
+
+ netop.cmd = NETWORK_OP_VIFGETINFO;
+ netop.u.vif_getinfo.domain = domid;
+ netop.u.vif_getinfo.vif = vifid;
+
+ if ( (rc = do_network_op(&netop)) >= 0 )
+ {
+ stats->tx_bytes = netop.u.vif_getinfo.total_bytes_sent;
+ stats->tx_pkts = netop.u.vif_getinfo.total_packets_sent;
+ stats->rx_bytes = netop.u.vif_getinfo.total_bytes_received;
+ stats->rx_pkts = netop.u.vif_getinfo.total_packets_received;
+ }
+
+ return rc;
+}
--- /dev/null
+Summary: Xen control interface library
+Name: xen-internal-library
+Version: 1.2
+Release: 1
+License: Xen
+Group: Xen
+BuildRoot: %{staging}
+%description
+Library to make it easier to access the Xen control interfaces.
+
+%pre
+%preun
+%install
+install -m 0755 -d $RPM_BUILD_ROOT/lib
+install -m 0755 libxc.a $RPM_BUILD_ROOT/lib/libxc.a
+install -m 0755 libxc.so $RPM_BUILD_ROOT/lib/libxc.so
+install -m 0755 -d $RPM_BUILD_ROOT/include
+install -m 0644 xc.h $RPM_BUILD_ROOT/include/xc.h
+%clean
+%post
+%postun
+%files
+%defattr(-,root,root)
+%dir /lib
+/lib/libxc.a
+/lib/libxc.so
+%dir /include
+/include/xc.h
--- /dev/null
+/******************************************************************************
+ * xc.h
+ *
+ * A library for low-level access to the Xen control interfaces.
+ *
+ * Copyright (c) 2003, K A Fraser.
+ */
+
+#ifndef __XC_H__
+#define __XC_H__
+
+int xc_interface_open(void);
+int xc_interface_close(void);
+
+typedef struct {
+ unsigned int domid;
+ unsigned int cpu;
+ int has_cpu;
+ int stopped;
+ unsigned long nr_pages;
+ unsigned long long cpu_time;
+#define XC_DOMINFO_MAXNAME 16
+ char name[XC_DOMINFO_MAXNAME];
+} xc_dominfo_t;
+
+int xc_domain_create(unsigned int mem_kb, const char *name);
+int xc_domain_start(unsigned int domid);
+int xc_domain_stop(unsigned int domid);
+int xc_domain_destroy(unsigned int domid, int force);
+int xc_domain_getinfo(unsigned int first_domid,
+ unsigned int max_doms,
+ xc_dominfo_t *info);
+
+int xc_linux_save(unsigned int domid, const char *state_file, int verbose);
+int xc_linux_restore(const char *state_file, int verbose);
+int xc_linux_build(unsigned int domid,
+ const char *image_name,
+ const char *ramdisk_name,
+ const char *cmdline,
+ int verbose);
+
+int xc_bvtsched_global_set(unsigned long ctx_allow);
+int xc_bvtsched_domain_set(unsigned int domid,
+ unsigned long mcuadv,
+ unsigned long warp,
+ unsigned long warpl,
+ unsigned long warpu);
+
+typedef struct {
+ unsigned long credit_bytes;
+ unsigned long credit_usec;
+} xc_vif_sched_params_t;
+
+typedef struct {
+ unsigned long long tx_bytes, tx_pkts;
+ unsigned long long rx_bytes, rx_pkts;
+} xc_vif_stats_t;
+
+int xc_vif_scheduler_set(unsigned int domid,
+ unsigned int vifid,
+ xc_vif_sched_params_t *params);
+int xc_vif_scheduler_get(unsigned int domid,
+ unsigned int vifid,
+ xc_vif_sched_params_t *params);
+int xc_vif_stats_get(unsigned int domid,
+ unsigned int vifid,
+ xc_vif_stats_t *stats);
+
+typedef struct {
+#define XC_VBDDOM_PROBE_ALL (~0U)
+ unsigned int domid;
+ unsigned short vbdid;
+#define XC_VBDF_WRITEABLE (1<<0)
+ unsigned long flags;
+ unsigned long nr_sectors;
+} xc_vbd_t;
+
+
+int xc_vbd_create(unsigned int domid, unsigned short vbdid, int writeable);
+int xc_vbd_destroy(unsigned int domid, unsigned short vbdid);
+int xc_vbd_add_extent(unsigned int domid,
+ unsigned short vbdid,
+ unsigned short real_device,
+ unsigned long start_sector,
+ unsigned long nr_sectors);
+int xc_vbd_delete_extent(unsigned int domid,
+ unsigned short vbdid,
+ unsigned short real_device,
+ unsigned long start_sector,
+ unsigned long nr_sectors);
+int xc_vbd_probe(unsigned int domid,
+ unsigned short vbdid,
+ unsigned int max_vbds,
+ xc_vbd_t *vbds);
+
+int xc_readconsolering(char *str, unsigned int max_chars, int clear);
+
+
+#endif /* __XC_H__ */
+++ /dev/null
-
-CC = gcc
-CFLAGS = -c -Wall -O3
-CFLAGS += -I../../xen/include -I../../xenolinux-sparse/include
-
-HDRS = $(wildcard *.h)
-OBJS = $(patsubst %.c,%.o,$(wildcard libxi_*.c))
-
-LIBS = libxi.a libxi.so
-
-all: check-for-zlib $(LIBS)
- ranlib libxi.a
-
-check-for-zlib:
- @if [ ! -e /usr/include/zlib.h ]; then \
- echo "***********************************************************"; \
- echo "ERROR: install zlib header files (http://www.gzip.org/zlib)"; \
- echo "***********************************************************"; \
- false; \
- fi
-
-install: all
- mkdir -p ../../../install/lib
- mkdir -p ../../../install/include
- cp -a $(LIBS) ../../../install/lib
- for i in $(LIBS) do ; chmod 755 ../../../install/bin/$i ; done
- cp -a xi.h ../../../install/include
- chmod 644 ../../../install/include/xi.h
-
-clean:
- $(RM) *.a *.so *.o *.rpm $(LIBS)
-
-rpm: all
- rm -rf staging
- mkdir staging
- mkdir staging/i386
- rpmbuild --define "staging$$PWD/staging" --define '_builddir.' \
- --define "_rpmdir$$PWD/staging" -bb rpm.spec
- mv staging/i386/*.rpm .
- rm -rf staging
-
-libxi.so: $(OBJS)
- $(LD) -shared -o $@ $^ -lz
-
-libxi.a: libxi.a($(OBJS))
-
-%.o: %.c $(HDRS) Makefile
- $(CC) $(CFLAGS) -o $@ $<
+++ /dev/null
-/******************************************************************************
- * libxi_bvtsched.c
- *
- * API for manipulating parameters of the Borrowed Virtual Time scheduler.
- *
- * Copyright (c) 2003, K A Fraser.
- */
-
-#include "libxi_private.h"
-
-int xi_bvtsched_global_set(unsigned long ctx_allow)
-{
- dom0_op_t op;
- op.cmd = DOM0_BVTCTL;
- op.u.bvtctl.ctx_allow = ctx_allow;
- return do_dom0_op(&op);
-}
-
-int xi_bvtsched_domain_set(unsigned int domid,
- unsigned long mcuadv,
- unsigned long warp,
- unsigned long warpl,
- unsigned long warpu)
-{
- dom0_op_t op;
- op.cmd = DOM0_ADJUSTDOM;
- op.u.adjustdom.domain = domid;
- op.u.adjustdom.mcu_adv = mcuadv;
- op.u.adjustdom.warp = warp;
- op.u.adjustdom.warpl = warpl;
- op.u.adjustdom.warpu = warpu;
- return do_dom0_op(&op);
-}
+++ /dev/null
-/******************************************************************************
- * libxi_domain.c
- *
- * API for manipulating and obtaining information on domains.
- *
- * Copyright (c) 2003, K A Fraser.
- */
-
-#include "libxi_private.h"
-
-int xi_domain_create(unsigned int mem_kb, const char *name)
-{
- int err;
- dom0_op_t op;
-
- op.cmd = DOM0_CREATEDOMAIN;
- op.u.createdomain.memory_kb = mem_kb;
- strncpy(op.u.createdomain.name, name, MAX_DOMAIN_NAME);
- op.u.createdomain.name[MAX_DOMAIN_NAME-1] = '\0';
-
- err = do_dom0_op(&op);
-
- return (err < 0) ? err : op.u.createdomain.domain;
-}
-
-
-int xi_domain_start(unsigned int domid)
-{
- dom0_op_t op;
- op.cmd = DOM0_STARTDOMAIN;
- op.u.startdomain.domain = domid;
- return do_dom0_op(&op);
-}
-
-
-int xi_domain_stop(unsigned int domid)
-{
- dom0_op_t op;
- op.cmd = DOM0_STOPDOMAIN;
- op.u.stopdomain.domain = domid;
- return do_dom0_op(&op);
-}
-
-
-int xi_domain_destroy(unsigned int domid, int force)
-{
- dom0_op_t op;
- op.cmd = DOM0_DESTROYDOMAIN;
- op.u.destroydomain.domain = domid;
- op.u.destroydomain.force = !!force;
- return do_dom0_op(&op);
-}
-
-int xi_domain_getinfo(unsigned int first_domid,
- unsigned int max_doms,
- xi_dominfo_t *info)
-{
- unsigned int nr_doms, next_domid = first_domid;
- dom0_op_t op;
-
- for ( nr_doms = 0; nr_doms < max_doms; nr_doms++ )
- {
- op.cmd = DOM0_GETDOMAININFO;
- op.u.getdomaininfo.domain = next_domid;
- if ( do_dom0_op(&op) < 0 )
- break;
- info->domid = op.u.getdomaininfo.domain;
- info->cpu = op.u.getdomaininfo.processor;
- info->has_cpu = op.u.getdomaininfo.has_cpu;
- info->stopped = (op.u.getdomaininfo.state == DOMSTATE_STOPPED);
- info->nr_pages = op.u.getdomaininfo.tot_pages;
- info->cpu_time = op.u.getdomaininfo.cpu_time;
- strncpy(info->name, op.u.getdomaininfo.name, XI_DOMINFO_MAXNAME);
- info->name[XI_DOMINFO_MAXNAME-1] = '\0';
-
- next_domid = op.u.getdomaininfo.domain + 1;
- }
-
- return nr_doms;
-}
+++ /dev/null
-/******************************************************************************
- * libxi_linux_build.c
- */
-
-#include "libxi_private.h"
-#include <zlib.h>
-
-/* This string is written to the head of every guest kernel image. */
-#define GUEST_SIG "XenoGues"
-#define SIG_LEN 8
-
-#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
-#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
-
-static long get_tot_pages(int domid)
-{
- dom0_op_t op;
- op.cmd = DOM0_GETDOMAININFO;
- op.u.getdomaininfo.domain = domid;
- return (do_dom0_op(&op) < 0) ? -1 : op.u.getdomaininfo.tot_pages;
-}
-
-static int get_pfn_list(
- int domid, unsigned long *pfn_buf, unsigned long max_pfns)
-{
- dom0_op_t op;
- int ret;
- op.cmd = DOM0_GETMEMLIST;
- op.u.getmemlist.domain = domid;
- op.u.getmemlist.max_pfns = max_pfns;
- op.u.getmemlist.buffer = pfn_buf;
-
- if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 )
- return -1;
-
- ret = do_dom0_op(&op);
-
- (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long));
-
- return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
-}
-
-static int send_pgupdates(mmu_update_t *updates, int nr_updates)
-{
- int ret = -1;
- privcmd_hypercall_t hypercall;
-
- hypercall.op = __HYPERVISOR_mmu_update;
- hypercall.arg[0] = (unsigned long)updates;
- hypercall.arg[1] = (unsigned long)nr_updates;
-
- if ( mlock(updates, nr_updates * sizeof(*updates)) != 0 )
- goto out1;
-
- if ( do_xen_hypercall(&hypercall) < 0 )
- goto out2;
-
- ret = 0;
-
- out2: (void)munlock(updates, nr_updates * sizeof(*updates));
- out1: return ret;
-}
-
-/* Read the kernel header, extracting the image size and load address. */
-static int read_kernel_header(gzFile gfd, long dom_size,
- unsigned long *load_addr, int verbose)
-{
- char signature[SIG_LEN];
-
- gzread(gfd, signature, SIG_LEN);
- if ( strncmp(signature, GUEST_SIG, SIG_LEN) )
- {
- if ( verbose )
- ERROR("Kernel image does not contain required signature");
- return -1;
- }
-
- /* Read the load address which immediately follows the Xeno signature. */
- gzread(gfd, load_addr, sizeof(unsigned long));
-
- return 0;
-}
-
-static int copy_to_domain_page(unsigned long dst_pfn, void *src_page)
-{
- void *vaddr = map_pfn(dst_pfn);
- if ( vaddr == NULL )
- return -1;
- memcpy(vaddr, src_page, PAGE_SIZE);
- unmap_pfn(vaddr);
- return 0;
-}
-
-static int setup_guestos(
- int dom, gzFile kernel_gfd, int initrd_fd, unsigned long tot_pages,
- unsigned long *virt_startinfo_addr, unsigned long virt_load_addr,
- dom0_builddomain_t *builddomain, const char *cmdline,
- unsigned long shared_info_frame, int verbose)
-{
- l1_pgentry_t *vl1tab = NULL, *vl1e = NULL;
- l2_pgentry_t *vl2tab = NULL, *vl2e = NULL;
- unsigned long *page_array = NULL;
- mmu_update_t *pgt_update_arr = NULL, *pgt_updates = NULL;
- int alloc_index, num_pt_pages;
- unsigned long l2tab;
- unsigned long l1tab = 0;
- unsigned long num_pgt_updates = 0;
- unsigned long count, pt_start, i, j;
- unsigned long initrd_addr = 0, initrd_len = 0;
- start_info_t *start_info;
- shared_info_t *shared_info;
- unsigned long ksize;
-
- memset(builddomain, 0, sizeof(*builddomain));
-
- if ( init_pfn_mapper() < 0 )
- goto error_out;
-
- pgt_updates = malloc((tot_pages + 1024) * 3 * sizeof(mmu_update_t));
- page_array = malloc(tot_pages * sizeof(unsigned long));
- pgt_update_arr = pgt_updates;
- if ( (pgt_update_arr == NULL) || (page_array == NULL) )
- {
- if ( verbose )
- PERROR("Could not allocate memory");
- goto error_out;
- }
-
- if ( get_pfn_list(dom, page_array, tot_pages) != tot_pages )
- {
- if ( verbose )
- PERROR("Could not get the page frame list");
- goto error_out;
- }
-
- /* Load the guest OS image. Let it take no more than 1/2 memory.*/
- for ( i = 0; i < ((tot_pages/2)*PAGE_SIZE); i += PAGE_SIZE )
- {
- char page[PAGE_SIZE];
- int size;
- if ( (size = gzread(kernel_gfd, page, PAGE_SIZE)) == -1 )
- {
- if ( verbose )
- PERROR("Error reading kernel image, could not"
- " read the whole image.");
- goto error_out;
- }
- if ( size == 0 )
- goto kernel_copied;
- copy_to_domain_page(page_array[i>>PAGE_SHIFT], page);
- }
- if ( verbose )
- ERROR("Kernel too big to safely fit in domain memory");
- goto error_out;
-
- kernel_copied:
- /* ksize is kernel-image size rounded up to a page boundary. */
- ksize = i;
-
- /* Load the initial ramdisk image. */
- if ( initrd_fd >= 0 )
- {
- struct stat stat;
- unsigned long isize;
-
- if ( fstat(initrd_fd, &stat) < 0 )
- {
- if ( verbose )
- PERROR("Could not stat the initrd image");
- goto error_out;
- }
- isize = stat.st_size;
- if ( (isize + ksize) > ((tot_pages/2) * PAGE_SIZE) )
- {
- if ( verbose )
- ERROR("Kernel/initrd too big to safely fit in domain memory");
- goto error_out;
- }
-
- initrd_addr = virt_load_addr + ksize;
- initrd_len = isize;
-
- for ( j = 0, i = ksize; j < isize; j += PAGE_SIZE, i += PAGE_SIZE )
- {
- char page[PAGE_SIZE];
- int size = ((isize-j) < PAGE_SIZE) ? (isize-j) : PAGE_SIZE;
- if ( read(initrd_fd, page, size) != size )
- {
- if ( verbose )
- PERROR("Error reading initrd image, could not"
- " read the whole image.");
- goto error_out;
- }
- copy_to_domain_page(page_array[i>>PAGE_SHIFT], page);
- }
- }
-
- alloc_index = tot_pages - 1;
-
- /* Count bottom-level PTs, rounding up. */
- num_pt_pages = (l1_table_offset(virt_load_addr) + tot_pages + 1023) / 1024;
-
- /* We must also count the page directory. */
- num_pt_pages++;
-
- /* Index of first PT page. */
- pt_start = tot_pages - num_pt_pages;
-
- /*
- * First allocate page for page dir. Allocation goes backwards from the end
- * of the allocated physical address space.
- */
- l2tab = page_array[alloc_index] << PAGE_SHIFT;
- alloc_index--;
- builddomain->ctxt.pt_base = l2tab;
-
- /*
- * Pin down l2tab addr as page dir page - causes hypervisor to provide
- * correct protection for the page
- */
- pgt_updates->ptr = l2tab | MMU_EXTENDED_COMMAND;
- pgt_updates->val = MMUEXT_PIN_L2_TABLE;
- pgt_updates++;
- num_pgt_updates++;
-
- /* Initialise the page tables. */
- if ( (vl2tab = map_pfn(l2tab >> PAGE_SHIFT)) == NULL )
- goto error_out;
- memset(vl2tab, 0, PAGE_SIZE);
- vl2e = vl2tab + l2_table_offset(virt_load_addr);
- for ( count = 0; count < tot_pages; count++ )
- {
- if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 )
- {
- l1tab = page_array[alloc_index] << PAGE_SHIFT;
- if ( (vl1tab = map_pfn(l1tab >> PAGE_SHIFT)) == NULL )
- goto error_out;
- memset(vl1tab, 0, PAGE_SIZE);
- alloc_index--;
-
- vl1e = vl1tab + l1_table_offset(virt_load_addr +
- (count << PAGE_SHIFT));
-
- /* make apropriate entry in the page directory */
- pgt_updates->ptr = (unsigned long)vl2e;
- pgt_updates->val = l1tab | L2_PROT;
- pgt_updates++;
- num_pgt_updates++;
- vl2e++;
- }
-
- if ( count < pt_start )
- {
- pgt_updates->ptr = (unsigned long)vl1e;
- pgt_updates->val = (page_array[count] << PAGE_SHIFT) | L1_PROT;
- pgt_updates++;
- num_pgt_updates++;
- vl1e++;
- }
- else
- {
- pgt_updates->ptr = (unsigned long)vl1e;
- pgt_updates->val =
- ((page_array[count] << PAGE_SHIFT) | L1_PROT) & ~_PAGE_RW;
- pgt_updates++;
- num_pgt_updates++;
- vl1e++;
- }
-
- pgt_updates->ptr =
- (page_array[count] << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
- pgt_updates->val = count;
- pgt_updates++;
- num_pgt_updates++;
- }
-
- *virt_startinfo_addr =
- virt_load_addr + ((alloc_index-1) << PAGE_SHIFT);
-
- start_info = map_pfn(page_array[alloc_index-1]);
- memset(start_info, 0, sizeof(*start_info));
- start_info->pt_base = virt_load_addr + ((tot_pages-1) << PAGE_SHIFT);
- start_info->mod_start = initrd_addr;
- start_info->mod_len = initrd_len;
- start_info->nr_pages = tot_pages;
- start_info->shared_info = shared_info_frame << PAGE_SHIFT;
- start_info->dom_id = dom;
- start_info->flags = 0;
- strncpy(start_info->cmd_line, cmdline, MAX_CMD_LEN);
- start_info->cmd_line[MAX_CMD_LEN-1] = '\0';
-
- unmap_pfn(start_info);
-
- /* shared_info page starts its life empty. */
- shared_info = map_pfn(shared_info_frame);
- memset(shared_info, 0, PAGE_SIZE);
- unmap_pfn(shared_info);
-
- /* Send the page update requests down to the hypervisor. */
- if ( send_pgupdates(pgt_update_arr, num_pgt_updates) < 0 )
- goto error_out;
-
- free(page_array);
- free(pgt_update_arr);
- return 0;
-
- error_out:
- if ( page_array == NULL )
- free(page_array);
- if ( pgt_update_arr == NULL )
- free(pgt_update_arr);
- return -1;
-}
-
-int xi_domain_build(unsigned int domid,
- const char *image_name,
- const char *ramdisk_name,
- const char *cmdline,
- int verbose)
-{
- dom0_op_t launch_op, op;
- unsigned long load_addr;
- long tot_pages;
- int kernel_fd, initrd_fd = -1;
- gzFile kernel_gfd;
- int rc, i;
- full_execution_context_t *ctxt;
- unsigned long virt_startinfo_addr;
-
- if ( (tot_pages = get_tot_pages(domid)) < 0 )
- {
- if ( verbose )
- PERROR("Could not find total pages for domain");
- return 1;
- }
-
- kernel_fd = open(image_name, O_RDONLY);
- if ( kernel_fd < 0 )
- {
- if ( verbose )
- PERROR("Could not open kernel image");
- return 1;
- }
-
- if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL )
- {
- if ( verbose )
- PERROR("Could not allocate decompression state for state file");
- close(kernel_fd);
- return 1;
- }
-
- rc = read_kernel_header(kernel_gfd,
- tot_pages << (PAGE_SHIFT - 10),
- &load_addr, verbose);
- if ( rc < 0 )
- goto error_out;
-
- if ( (load_addr & (PAGE_SIZE-1)) != 0 )
- {
- if ( verbose )
- ERROR("We can only deal with page-aligned load addresses");
- goto error_out;
- }
-
- if ( (load_addr + (tot_pages << PAGE_SHIFT)) > HYPERVISOR_VIRT_START )
- {
- if ( verbose )
- ERROR("Cannot map all domain memory without hitting Xen space");
- goto error_out;
- }
-
- if ( ramdisk_name != NULL )
- {
- initrd_fd = open(ramdisk_name, O_RDONLY);
- if ( initrd_fd < 0 )
- {
- if ( verbose )
- PERROR("Could not open the initial ramdisk image");
- goto error_out;
- }
- }
-
- op.cmd = DOM0_GETDOMAININFO;
- op.u.getdomaininfo.domain = domid;
- if ( (do_dom0_op(&op) < 0) || (op.u.getdomaininfo.domain != domid) )
- {
- if ( verbose )
- PERROR("Could not get info on domain");
- goto error_out;
- }
- if ( (op.u.getdomaininfo.state != DOMSTATE_STOPPED) ||
- (op.u.getdomaininfo.ctxt.pt_base != 0) )
- {
- if ( verbose )
- ERROR("Domain is already constructed");
- goto error_out;
- }
-
- if ( setup_guestos(domid, kernel_gfd, initrd_fd, tot_pages,
- &virt_startinfo_addr,
- load_addr, &launch_op.u.builddomain, cmdline,
- op.u.getdomaininfo.shared_info_frame, verbose) < 0 )
- {
- if ( verbose )
- ERROR("Error constructing guest OS");
- goto error_out;
- }
-
- if ( initrd_fd >= 0 )
- close(initrd_fd);
- gzclose(kernel_gfd);
-
- ctxt = &launch_op.u.builddomain.ctxt;
-
- ctxt->flags = 0;
-
- /*
- * Initial register values:
- * DS,ES,FS,GS = FLAT_RING1_DS
- * CS:EIP = FLAT_RING1_CS:start_pc
- * SS:ESP = FLAT_RING1_DS:start_stack
- * ESI = start_info
- * [EAX,EBX,ECX,EDX,EDI,EBP are zero]
- * EFLAGS = IF | 2 (bit 1 is reserved and should always be 1)
- */
- ctxt->i386_ctxt.ds = FLAT_RING1_DS;
- ctxt->i386_ctxt.es = FLAT_RING1_DS;
- ctxt->i386_ctxt.fs = FLAT_RING1_DS;
- ctxt->i386_ctxt.gs = FLAT_RING1_DS;
- ctxt->i386_ctxt.ss = FLAT_RING1_DS;
- ctxt->i386_ctxt.cs = FLAT_RING1_CS;
- ctxt->i386_ctxt.eip = load_addr;
- ctxt->i386_ctxt.esp = virt_startinfo_addr;
- ctxt->i386_ctxt.esi = virt_startinfo_addr;
- ctxt->i386_ctxt.eflags = (1<<9) | (1<<2);
-
- /* FPU is set up to default initial state. */
- memset(ctxt->i387_ctxt, 0, sizeof(ctxt->i387_ctxt));
-
- /* Virtual IDT is empty at start-of-day. */
- for ( i = 0; i < 256; i++ )
- {
- ctxt->trap_ctxt[i].vector = i;
- ctxt->trap_ctxt[i].cs = FLAT_RING1_CS;
- }
- ctxt->fast_trap_idx = 0;
-
- /* No LDT. */
- ctxt->ldt_ents = 0;
-
- /* Use the default Xen-provided GDT. */
- ctxt->gdt_ents = 0;
-
- /* Ring 1 stack is the initial stack. */
- ctxt->ring1_ss = FLAT_RING1_DS;
- ctxt->ring1_esp = virt_startinfo_addr;
-
- /* No debugging. */
- memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg));
-
- /* No callback handlers. */
- ctxt->event_callback_cs = FLAT_RING1_CS;
- ctxt->event_callback_eip = 0;
- ctxt->failsafe_callback_cs = FLAT_RING1_CS;
- ctxt->failsafe_callback_eip = 0;
-
- launch_op.u.builddomain.domain = domid;
- launch_op.u.builddomain.num_vifs = 1;
-
- launch_op.cmd = DOM0_BUILDDOMAIN;
- rc = do_dom0_op(&launch_op);
-
- return rc;
-
- error_out:
- if ( initrd_fd >= 0 )
- close(initrd_fd);
- gzclose(kernel_gfd);
- return -1;
-}
+++ /dev/null
-/******************************************************************************
- * libxi_linux_restore.c
- *
- * Restore the state of a Xenolinux session.
- *
- * Copyright (c) 2003, K A Fraser.
- */
-
-#include "libxi_private.h"
-#include <asm-xeno/suspend.h>
-#include <zlib.h>
-
-/* This may allow us to create a 'quiet' command-line option, if necessary. */
-#define verbose_printf(_f, _a...) \
- do { \
- if ( !verbose ) break; \
- printf( _f , ## _a ); \
- fflush(stdout); \
- } while ( 0 )
-
-static int get_pfn_list(
- int domain_id, unsigned long *pfn_buf, unsigned long max_pfns)
-{
- dom0_op_t op;
- int ret;
- op.cmd = DOM0_GETMEMLIST;
- op.u.getmemlist.domain = domain_id;
- op.u.getmemlist.max_pfns = max_pfns;
- op.u.getmemlist.buffer = pfn_buf;
-
- if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 )
- {
- PERROR("Could not lock pfn list buffer");
- return -1;
- }
-
- ret = do_dom0_op(&op);
-
- (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long));
-
- return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
-}
-
-#define MAX_MMU_UPDATES 1024
-
-static int flush_mmu_updates(mmu_update_t *mmu_updates,
- int *mmu_update_idx)
-{
- int err = 0;
- privcmd_hypercall_t hypercall;
-
- if ( *mmu_update_idx == 0 )
- return 0;
-
- hypercall.op = __HYPERVISOR_mmu_update;
- hypercall.arg[0] = (unsigned long)mmu_updates;
- hypercall.arg[1] = (unsigned long)*mmu_update_idx;
-
- if ( mlock(mmu_updates, sizeof(mmu_updates)) != 0 )
- {
- PERROR("Could not lock pagetable update array");
- err = 1;
- goto out;
- }
-
- if ( do_xen_hypercall(&hypercall) < 0 )
- {
- ERROR("Failure when submitting mmu updates");
- err = 1;
- }
-
- *mmu_update_idx = 0;
-
- (void)munlock(mmu_updates, sizeof(mmu_updates));
-
- out:
- return err;
-}
-
-static int add_mmu_update(mmu_update_t *mmu_updates,
- int *mmu_update_idx,
- unsigned long ptr,
- unsigned long val)
-{
- mmu_updates[*mmu_update_idx].ptr = ptr;
- mmu_updates[*mmu_update_idx].val = val;
- if ( ++*mmu_update_idx == MAX_MMU_UPDATES )
- return flush_mmu_updates(mmu_updates, mmu_update_idx);
- return 0;
-}
-
-static int checked_read(gzFile fd, void *buf, size_t count)
-{
- int rc;
- while ( ((rc = gzread(fd, buf, count)) == -1) && (errno == EINTR) )
- continue;
- return rc == count;
-}
-
-int xi_linux_restore(const char *state_file, int verbose)
-{
- dom0_op_t op;
- int rc = 1, i, j;
- unsigned long mfn, pfn, dom = 0;
- unsigned int prev_pc, this_pc;
-
- /* Number of page frames in use by this XenoLinux session. */
- unsigned long nr_pfns;
-
- /* The new domain's shared-info frame number. */
- unsigned long shared_info_frame;
- unsigned char shared_info[PAGE_SIZE]; /* saved contents from file */
-
- /* A copy of the CPU context of the guest. */
- full_execution_context_t ctxt;
-
- /* First 16 bytes of the state file must contain 'XenoLinuxSuspend'. */
- char signature[16];
-
- /* A copy of the domain's name. */
- char name[MAX_DOMAIN_NAME];
-
- /* A table containg the type of each PFN (/not/ MFN!). */
- unsigned long *pfn_type = NULL;
-
- /* A temporary mapping, and a copy, of one frame of guest memory. */
- unsigned long *ppage, page[1024];
-
- /* A copy of the pfn-to-mfn table frame list. */
- unsigned long pfn_to_mfn_frame_list[1024];
-
- /* A table mapping each PFN to its new MFN. */
- unsigned long *pfn_to_mfn_table = NULL;
-
- /* A temporary mapping of the guest's suspend record. */
- suspend_record_t *p_srec;
-
- /* The name and descriptor of the file that we are reading from. */
- int fd;
- gzFile gfd;
-
- mmu_update_t mmu_updates[MAX_MMU_UPDATES];
- int mmu_update_idx = 0;
-
- if ( (fd = open(state_file, O_RDONLY)) == -1 )
- {
- PERROR("Could not open state file for reading");
- return 1;
- }
-
- if ( (gfd = gzdopen(fd, "rb")) == NULL )
- {
- ERROR("Could not allocate decompression state for state file");
- close(fd);
- return 1;
- }
-
- /* Start writing out the saved-domain record. */
- if ( !checked_read(gfd, signature, 16) ||
- (memcmp(signature, "XenoLinuxSuspend", 16) != 0) )
- {
- ERROR("Unrecognised state format -- no signature found");
- goto out;
- }
-
- if ( !checked_read(gfd, name, sizeof(name)) ||
- !checked_read(gfd, &nr_pfns, sizeof(unsigned long)) ||
- !checked_read(gfd, &ctxt, sizeof(ctxt)) ||
- !checked_read(gfd, shared_info, PAGE_SIZE) ||
- !checked_read(gfd, pfn_to_mfn_frame_list, PAGE_SIZE) )
- {
- ERROR("Error when reading from state file");
- goto out;
- }
-
- for ( i = 0; i < MAX_DOMAIN_NAME; i++ )
- {
- if ( name[i] == '\0' ) break;
- if ( name[i] & 0x80 )
- {
- ERROR("Random characters in domain name");
- goto out;
- }
- }
- name[MAX_DOMAIN_NAME-1] = '\0';
-
- if ( nr_pfns > 1024*1024 )
- {
- ERROR("Invalid state file -- pfn count out of range");
- goto out;
- }
-
- /* We want zeroed memory so use calloc rather than malloc. */
- pfn_to_mfn_table = calloc(1, 4 * nr_pfns);
- pfn_type = calloc(1, 4 * nr_pfns);
-
- if ( (pfn_to_mfn_table == NULL) || (pfn_type == NULL) )
- {
- errno = ENOMEM;
- goto out;
- }
-
- if ( !checked_read(gfd, pfn_type, 4 * nr_pfns) )
- {
- ERROR("Error when reading from state file");
- goto out;
- }
-
- /* Create a new domain of the appropriate size, and find it's dom_id. */
- op.cmd = DOM0_CREATEDOMAIN;
- op.u.createdomain.memory_kb = nr_pfns * (PAGE_SIZE / 1024);
- memcpy(op.u.createdomain.name, name, MAX_DOMAIN_NAME);
- if ( do_dom0_op(&op) < 0 )
- {
- ERROR("Could not create new domain");
- goto out;
- }
- dom = op.u.createdomain.domain;
-
- /* Get the domain's shared-info frame. */
- op.cmd = DOM0_GETDOMAININFO;
- op.u.getdomaininfo.domain = dom;
- if ( do_dom0_op(&op) < 0 )
- {
- ERROR("Could not get information on new domain");
- goto out;
- }
- shared_info_frame = op.u.getdomaininfo.shared_info_frame;
-
- if ( init_pfn_mapper() < 0 )
- goto out;
-
- /* Copy saved contents of shared-info page. No checking needed. */
- ppage = map_pfn(shared_info_frame);
- memcpy(ppage, shared_info, PAGE_SIZE);
- unmap_pfn(ppage);
-
- /* Build the pfn-to-mfn table. We choose MFN ordering returned by Xen. */
- if ( get_pfn_list(dom, pfn_to_mfn_table, nr_pfns) != nr_pfns )
- {
- ERROR("Did not read correct number of frame numbers for new dom");
- goto out;
- }
-
- verbose_printf("Reloading memory pages: 0%%");
-
- /*
- * Now simply read each saved frame into its new machine frame.
- * We uncanonicalise page tables as we go.
- */
- prev_pc = 0;
- for ( i = 0; i < nr_pfns; i++ )
- {
- this_pc = (i * 100) / nr_pfns;
- if ( (this_pc - prev_pc) >= 5 )
- {
- verbose_printf("\b\b\b\b%3d%%", this_pc);
- prev_pc = this_pc;
- }
-
- mfn = pfn_to_mfn_table[i];
-
- if ( !checked_read(gfd, page, PAGE_SIZE) )
- {
- ERROR("Error when reading from state file");
- goto out;
- }
-
- ppage = map_pfn(mfn);
- switch ( pfn_type[i] )
- {
- case L1TAB:
- memset(ppage, 0, PAGE_SIZE);
- if ( add_mmu_update(mmu_updates, &mmu_update_idx,
- (mfn<<PAGE_SHIFT) | MMU_EXTENDED_COMMAND,
- MMUEXT_PIN_L1_TABLE) )
- goto out;
- for ( j = 0; j < 1024; j++ )
- {
- if ( page[j] & _PAGE_PRESENT )
- {
- if ( (pfn = page[j] >> PAGE_SHIFT) >= nr_pfns )
- {
- ERROR("Frame number in page table is out of range");
- goto out;
- }
- if ( (pfn_type[pfn] != NONE) && (page[j] & _PAGE_RW) )
- {
- ERROR("Write access requested for a restricted frame");
- goto out;
- }
- page[j] &= (PAGE_SIZE - 1) & ~(_PAGE_GLOBAL | _PAGE_PAT);
- page[j] |= pfn_to_mfn_table[pfn] << PAGE_SHIFT;
- }
- if ( add_mmu_update(mmu_updates, &mmu_update_idx,
- (unsigned long)&ppage[j], page[j]) )
- goto out;
- }
- break;
- case L2TAB:
- memset(ppage, 0, PAGE_SIZE);
- if ( add_mmu_update(mmu_updates, &mmu_update_idx,
- (mfn<<PAGE_SHIFT) | MMU_EXTENDED_COMMAND,
- MMUEXT_PIN_L2_TABLE) )
- goto out;
- for ( j = 0; j < (HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT); j++ )
- {
- if ( page[j] & _PAGE_PRESENT )
- {
- if ( (pfn = page[j] >> PAGE_SHIFT) >= nr_pfns )
- {
- ERROR("Frame number in page table is out of range");
- goto out;
- }
- if ( pfn_type[pfn] != L1TAB )
- {
- ERROR("Page table mistyping");
- goto out;
- }
- /* Haven't reached the L1 table yet. Ensure it is safe! */
- if ( pfn > i )
- {
- unsigned long **l1 = map_pfn(pfn_to_mfn_table[pfn]);
- memset(l1, 0, PAGE_SIZE);
- unmap_pfn(l1);
- }
- page[j] &= (PAGE_SIZE - 1) & ~(_PAGE_GLOBAL | _PAGE_PSE);
- page[j] |= pfn_to_mfn_table[pfn] << PAGE_SHIFT;
- }
- if ( add_mmu_update(mmu_updates, &mmu_update_idx,
- (unsigned long)&ppage[j], page[j]) )
- goto out;
- }
- break;
- default:
- memcpy(ppage, page, PAGE_SIZE);
- break;
- }
- /* NB. Must flush before unmapping page, as pass VAs to Xen. */
- if ( flush_mmu_updates(mmu_updates, &mmu_update_idx) )
- goto out;
- unmap_pfn(ppage);
-
- if ( add_mmu_update(mmu_updates, &mmu_update_idx,
- (mfn<<PAGE_SHIFT) | MMU_MACHPHYS_UPDATE, i) )
- goto out;
- }
-
- if ( flush_mmu_updates(mmu_updates, &mmu_update_idx) )
- goto out;
-
- verbose_printf("\b\b\b\b100%%\nMemory reloaded.\n");
-
- /* Uncanonicalise the suspend-record frame number and poke resume rec. */
- pfn = ctxt.i386_ctxt.esi;
- if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NONE) )
- {
- ERROR("Suspend record frame number is bad");
- goto out;
- }
- ctxt.i386_ctxt.esi = mfn = pfn_to_mfn_table[pfn];
- p_srec = map_pfn(mfn);
- p_srec->resume_info.nr_pages = nr_pfns;
- p_srec->resume_info.shared_info = shared_info_frame << PAGE_SHIFT;
- p_srec->resume_info.dom_id = dom;
- p_srec->resume_info.flags = 0;
- unmap_pfn(p_srec);
-
- /* Uncanonicalise each GDT frame number. */
- if ( ctxt.gdt_ents > 8192 )
- {
- ERROR("GDT entry count out of range");
- goto out;
- }
- for ( i = 0; i < ctxt.gdt_ents; i += 512 )
- {
- pfn = ctxt.gdt_frames[i];
- if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NONE) )
- {
- ERROR("GDT frame number is bad");
- goto out;
- }
- ctxt.gdt_frames[i] = pfn_to_mfn_table[pfn];
- }
-
- /* Uncanonicalise the page table base pointer. */
- pfn = ctxt.pt_base >> PAGE_SHIFT;
- if ( (pfn >= nr_pfns) || (pfn_type[pfn] != L2TAB) )
- {
- ERROR("PT base is bad");
- goto out;
- }
- ctxt.pt_base = pfn_to_mfn_table[pfn] << PAGE_SHIFT;
-
- /* Uncanonicalise the pfn-to-mfn table frame-number list. */
- for ( i = 0; i < nr_pfns; i += 1024 )
- {
- unsigned long copy_size = (nr_pfns - i) * sizeof(unsigned long);
- if ( copy_size > PAGE_SIZE ) copy_size = PAGE_SIZE;
- pfn = pfn_to_mfn_frame_list[i/1024];
- if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NONE) )
- {
- ERROR("PFN-to-MFN frame number is bad");
- goto out;
- }
- ppage = map_pfn(pfn_to_mfn_table[pfn]);
- memcpy(ppage, &pfn_to_mfn_table[i], copy_size);
- unmap_pfn(ppage);
- }
-
- /*
- * Safety checking of saved context:
- * 1. i386_ctxt is fine, as Xen checks that on context switch.
- * 2. i387_ctxt is fine, as it can't hurt Xen.
- * 3. trap_ctxt needs the code selectors checked.
- * 4. fast_trap_idx is checked by Xen.
- * 5. ldt base must be page-aligned, no more than 8192 ents, ...
- * 6. gdt already done, and further checking is done by Xen.
- * 7. check that ring1_ss is safe.
- * 8. pt_base is already done.
- * 9. debugregs are checked by Xen.
- * 10. callback code selectors need checking.
- */
- for ( i = 0; i < 256; i++ )
- {
- ctxt.trap_ctxt[i].vector = i;
- if ( (ctxt.trap_ctxt[i].cs & 3) == 0 )
- ctxt.trap_ctxt[i].cs = FLAT_RING1_CS;
- }
- if ( (ctxt.ring1_ss & 3) == 0 )
- ctxt.ring1_ss = FLAT_RING1_DS;
- if ( (ctxt.event_callback_cs & 3) == 0 )
- ctxt.event_callback_cs = FLAT_RING1_CS;
- if ( (ctxt.failsafe_callback_cs & 3) == 0 )
- ctxt.failsafe_callback_cs = FLAT_RING1_CS;
- if ( ((ctxt.ldt_base & (PAGE_SIZE - 1)) != 0) ||
- (ctxt.ldt_ents > 8192) ||
- (ctxt.ldt_base > HYPERVISOR_VIRT_START) ||
- ((ctxt.ldt_base + ctxt.ldt_ents*8) > HYPERVISOR_VIRT_START) )
- {
- ERROR("Bad LDT base or size");
- goto out;
- }
-
- op.cmd = DOM0_BUILDDOMAIN;
- op.u.builddomain.domain = dom;
- op.u.builddomain.num_vifs = 1;
- memcpy(&op.u.builddomain.ctxt, &ctxt, sizeof(ctxt));
- rc = do_dom0_op(&op);
-
- out:
- if ( rc != 0 )
- {
- if ( dom != 0 )
- {
- op.cmd = DOM0_DESTROYDOMAIN;
- op.u.destroydomain.domain = dom;
- op.u.destroydomain.force = 1;
- (void)do_dom0_op(&op);
- }
- }
- else
- {
- /* Success: print the domain id. */
- verbose_printf("DOM=%ld\n", dom);
- }
-
- if ( pfn_to_mfn_table != NULL )
- free(pfn_to_mfn_table);
- if ( pfn_type != NULL )
- free(pfn_type);
-
- gzclose(gfd);
-
- return (rc == 0) ? dom : rc;
-}
+++ /dev/null
-/******************************************************************************
- * libxi_linux_save.c
- *
- * Save the state of a running Xenolinux session.
- *
- * Copyright (c) 2003, K A Fraser.
- */
-
-#include "libxi_private.h"
-#include <asm-xeno/suspend.h>
-#include <zlib.h>
-
-/* This may allow us to create a 'quiet' command-line option, if necessary. */
-#define verbose_printf(_f, _a...) \
- do { \
- if ( !verbose ) break; \
- printf( _f , ## _a ); \
- fflush(stdout); \
- } while ( 0 )
-
-/*
- * Returns TRUE if the given machine frame number has a unique mapping
- * in the guest's pseudophysical map.
- */
-#define MFN_IS_IN_PSEUDOPHYS_MAP(_mfn) \
- (((_mfn) < (1024*1024)) && \
- (pfn_to_mfn_table[mfn_to_pfn_table[_mfn]] == (_mfn)))
-
-/* Returns TRUE if MFN is successfully converted to a PFN. */
-#define translate_mfn_to_pfn(_pmfn) \
-({ \
- unsigned long mfn = *(_pmfn); \
- int _res = 1; \
- if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) ) \
- _res = 0; \
- else \
- *(_pmfn) = mfn_to_pfn_table[mfn]; \
- _res; \
-})
-
-static int check_pfn_ownership(unsigned long mfn, unsigned int dom)
-{
- dom0_op_t op;
- op.cmd = DOM0_GETPAGEFRAMEINFO;
- op.u.getpageframeinfo.pfn = mfn;
- if ( (do_dom0_op(&op) < 0) || (op.u.getpageframeinfo.domain != dom) )
- return 0;
- return 1;
-}
-
-#define GETPFN_ERR (~0U)
-static unsigned int get_pfn_type(unsigned long mfn)
-{
- dom0_op_t op;
- op.cmd = DOM0_GETPAGEFRAMEINFO;
- op.u.getpageframeinfo.pfn = mfn;
- if ( do_dom0_op(&op) < 0 )
- {
- PERROR("Unexpected failure when getting page frame info!");
- return GETPFN_ERR;
- }
- return op.u.getpageframeinfo.type;
-}
-
-static int checked_write(gzFile fd, void *buf, size_t count)
-{
- int rc;
- while ( ((rc = gzwrite(fd, buf, count)) == -1) && (errno = EINTR) )
- continue;
- return rc == count;
-}
-
-int xi_linux_save(unsigned int domid, const char *state_file, int verbose)
-{
- dom0_op_t op;
- int rc = 1, i, j;
- unsigned long mfn;
- unsigned int prev_pc, this_pc;
-
- /* Remember if we stopped the guest, so we can restart it on exit. */
- int we_stopped_it = 0;
-
- /* The new domain's shared-info frame number. */
- unsigned long shared_info_frame;
-
- /* A copy of the CPU context of the guest. */
- full_execution_context_t ctxt;
-
- /* A copy of the domain's name. */
- char name[MAX_DOMAIN_NAME];
-
- /* A table containg the type of each PFN (/not/ MFN!). */
- unsigned long *pfn_type = NULL;
-
- /* A temporary mapping, and a copy, of one frame of guest memory. */
- unsigned long *ppage, page[1024];
-
- /* A temporary mapping, and a copy, of the pfn-to-mfn table frame list. */
- unsigned long *p_pfn_to_mfn_frame_list, pfn_to_mfn_frame_list[1024];
- /* A temporary mapping of one frame in the above list. */
- unsigned long *pfn_to_mfn_frame;
-
- /* A table mapping each PFN to its current MFN. */
- unsigned long *pfn_to_mfn_table = NULL;
- /* A table mapping each current MFN to its canonical PFN. */
- unsigned long *mfn_to_pfn_table = NULL;
-
- /* A temporary mapping, and a copy, of the guest's suspend record. */
- suspend_record_t *p_srec, srec;
-
- /* The name and descriptor of the file that we are writing to. */
- int fd;
- gzFile gfd;
-
- if ( (fd = open(state_file, O_CREAT|O_EXCL|O_WRONLY, 0644)) == -1 )
- {
- PERROR("Could not open file for writing");
- return 1;
- }
-
- /*
- * Compression rate 1: we want speed over compression. We're mainly going
- * for those zero pages, after all.
- */
- if ( (gfd = gzdopen(fd, "wb1")) == NULL )
- {
- ERROR("Could not allocate compression state for state file");
- close(fd);
- return 1;
- }
-
- /* Ensure that the domain exists, and that it is stopped. */
- for ( ; ; )
- {
- op.cmd = DOM0_GETDOMAININFO;
- op.u.getdomaininfo.domain = domid;
- if ( (do_dom0_op(&op) < 0) || (op.u.getdomaininfo.domain != domid) )
- {
- PERROR("Could not get info on domain");
- goto out;
- }
-
- memcpy(&ctxt, &op.u.getdomaininfo.ctxt, sizeof(ctxt));
- memcpy(name, op.u.getdomaininfo.name, sizeof(name));
- shared_info_frame = op.u.getdomaininfo.shared_info_frame;
-
- if ( op.u.getdomaininfo.state == DOMSTATE_STOPPED )
- break;
-
- we_stopped_it = 1;
-
- op.cmd = DOM0_STOPDOMAIN;
- op.u.stopdomain.domain = domid;
- (void)do_dom0_op(&op);
-
- sleep(1);
- }
-
- /* A cheesy test to see whether the domain contains valid state. */
- if ( ctxt.pt_base == 0 )
- {
- ERROR("Domain is not in a valid Xenolinux state");
- goto out;
- }
-
- if ( init_pfn_mapper() < 0 )
- goto out;
-
- /* Is the suspend-record MFN actually valid for this domain? */
- if ( !check_pfn_ownership(ctxt.i386_ctxt.esi, domid) )
- {
- ERROR("Invalid state record pointer");
- goto out;
- }
-
- /* If the suspend-record MFN is okay then grab a copy of it to @srec. */
- p_srec = map_pfn(ctxt.i386_ctxt.esi);
- memcpy(&srec, p_srec, sizeof(srec));
- unmap_pfn(p_srec);
-
- if ( srec.nr_pfns > 1024*1024 )
- {
- ERROR("Invalid state record -- pfn count out of range");
- goto out;
- }
-
- if ( !check_pfn_ownership(srec.pfn_to_mfn_frame_list, domid) )
- {
- ERROR("Invalid pfn-to-mfn frame list pointer");
- goto out;
- }
-
- /* Grab a copy of the pfn-to-mfn table frame list. */
- p_pfn_to_mfn_frame_list = map_pfn(srec.pfn_to_mfn_frame_list);
- memcpy(pfn_to_mfn_frame_list, p_pfn_to_mfn_frame_list, PAGE_SIZE);
- unmap_pfn(p_pfn_to_mfn_frame_list);
-
- /* We want zeroed memory so use calloc rather than malloc. */
- mfn_to_pfn_table = calloc(1, 4 * 1024 * 1024);
- pfn_to_mfn_table = calloc(1, 4 * srec.nr_pfns);
- pfn_type = calloc(1, 4 * srec.nr_pfns);
-
- if ( (mfn_to_pfn_table == NULL) ||
- (pfn_to_mfn_table == NULL) ||
- (pfn_type == NULL) )
- {
- errno = ENOMEM;
- goto out;
- }
-
-
- /*
- * Construct the local pfn-to-mfn and mfn-to-pfn tables. On exit from this
- * loop we have each MFN mapped at most once. Note that there may be MFNs
- * that aren't mapped at all: we detect these by MFN_IS_IN_PSEUDOPHYS_MAP.
- */
- pfn_to_mfn_frame = NULL;
- for ( i = 0; i < srec.nr_pfns; i++ )
- {
- /* Each frameful of table frames must be checked & mapped on demand. */
- if ( (i & 1023) == 0 )
- {
- mfn = pfn_to_mfn_frame_list[i/1024];
- if ( !check_pfn_ownership(mfn, domid) )
- {
- ERROR("Invalid frame number if pfn-to-mfn frame list");
- goto out;
- }
- if ( pfn_to_mfn_frame != NULL )
- unmap_pfn(pfn_to_mfn_frame);
- pfn_to_mfn_frame = map_pfn(mfn);
- }
-
- mfn = pfn_to_mfn_frame[i & 1023];
-
- if ( !check_pfn_ownership(mfn, domid) )
- {
- ERROR("Invalid frame specified with pfn-to-mfn table");
- goto out;
- }
-
- /* Did we map this MFN already? That would be invalid! */
- if ( MFN_IS_IN_PSEUDOPHYS_MAP(mfn) )
- {
- ERROR("A machine frame appears twice in pseudophys space");
- goto out;
- }
-
- pfn_to_mfn_table[i] = mfn;
- mfn_to_pfn_table[mfn] = i;
-
- /* Query page type by MFN, but store it by PFN. */
- if ( (pfn_type[i] = get_pfn_type(mfn)) == GETPFN_ERR )
- goto out;
- }
-
- /* Canonicalise the suspend-record frame number. */
- if ( !translate_mfn_to_pfn(&ctxt.i386_ctxt.esi) )
- {
- ERROR("State record is not in range of pseudophys map");
- goto out;
- }
-
- /* Canonicalise each GDT frame number. */
- for ( i = 0; i < ctxt.gdt_ents; i += 512 )
- {
- if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[i]) )
- {
- ERROR("GDT frame is not in range of pseudophys map");
- goto out;
- }
- }
-
- /* Canonicalise the page table base pointer. */
- if ( !MFN_IS_IN_PSEUDOPHYS_MAP(ctxt.pt_base >> PAGE_SHIFT) )
- {
- ERROR("PT base is not in range of pseudophys map");
- goto out;
- }
- ctxt.pt_base = mfn_to_pfn_table[ctxt.pt_base >> PAGE_SHIFT] << PAGE_SHIFT;
-
- /* Canonicalise the pfn-to-mfn table frame-number list. */
- for ( i = 0; i < srec.nr_pfns; i += 1024 )
- {
- if ( !translate_mfn_to_pfn(&pfn_to_mfn_frame_list[i/1024]) )
- {
- ERROR("Frame # in pfn-to-mfn frame list is not in pseudophys");
- goto out;
- }
- }
-
- /* Start writing out the saved-domain record. */
- ppage = map_pfn(shared_info_frame);
- if ( !checked_write(gfd, "XenoLinuxSuspend", 16) ||
- !checked_write(gfd, name, sizeof(name)) ||
- !checked_write(gfd, &srec.nr_pfns, sizeof(unsigned long)) ||
- !checked_write(gfd, &ctxt, sizeof(ctxt)) ||
- !checked_write(gfd, ppage, PAGE_SIZE) ||
- !checked_write(gfd, pfn_to_mfn_frame_list, PAGE_SIZE) ||
- !checked_write(gfd, pfn_type, 4 * srec.nr_pfns) )
- {
- ERROR("Error when writing to state file");
- goto out;
- }
- unmap_pfn(ppage);
-
- verbose_printf("Saving memory pages: 0%%");
-
- /* Now write out each data page, canonicalising page tables as we go... */
- prev_pc = 0;
- for ( i = 0; i < srec.nr_pfns; i++ )
- {
- this_pc = (i * 100) / srec.nr_pfns;
- if ( (this_pc - prev_pc) >= 5 )
- {
- verbose_printf("\b\b\b\b%3d%%", this_pc);
- prev_pc = this_pc;
- }
-
- mfn = pfn_to_mfn_table[i];
-
- ppage = map_pfn(mfn);
- memcpy(page, ppage, PAGE_SIZE);
- unmap_pfn(ppage);
-
- if ( (pfn_type[i] == L1TAB) || (pfn_type[i] == L2TAB) )
- {
- for ( j = 0;
- j < ((pfn_type[i] == L2TAB) ?
- (HYPERVISOR_VIRT_START >> L2_PAGETABLE_SHIFT) : 1024);
- j++ )
- {
- if ( !(page[j] & _PAGE_PRESENT) ) continue;
- mfn = page[j] >> PAGE_SHIFT;
- if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) )
- {
- ERROR("Frame number in pagetable page is invalid");
- goto out;
- }
- page[j] &= PAGE_SIZE - 1;
- page[j] |= mfn_to_pfn_table[mfn] << PAGE_SHIFT;
- }
- }
-
- if ( !checked_write(gfd, page, PAGE_SIZE) )
- {
- ERROR("Error when writing to state file");
- goto out;
- }
- }
-
- verbose_printf("\b\b\b\b100%%\nMemory saved.\n");
-
- /* Success! */
- rc = 0;
-
- out:
- /* Restart the domain if we had to stop it to save its state. */
- if ( we_stopped_it )
- {
- op.cmd = DOM0_STARTDOMAIN;
- op.u.startdomain.domain = domid;
- (void)do_dom0_op(&op);
- }
-
- gzclose(gfd);
-
- if ( pfn_to_mfn_table != NULL )
- free(pfn_to_mfn_table);
- if ( mfn_to_pfn_table != NULL )
- free(mfn_to_pfn_table);
- if ( pfn_type != NULL )
- free(pfn_type);
-
- /* On error, make sure the file is deleted. */
- if ( rc != 0 )
- unlink(state_file);
-
- return !!rc;
-}
+++ /dev/null
-/******************************************************************************
- * libxi_misc.c
- *
- * Miscellaneous control interface functions.
- */
-
-#include "libxi_private.h"
-
-int privcmd_fd = -1;
-
-int xi_interface_open(void)
-{
- if ( (privcmd_fd == -1) &&
- ((privcmd_fd = open("/proc/xeno/privcmd", O_RDWR)) < 0) )
- {
- privcmd_fd = -1;
- return -1;
- }
- return 0;
-}
-
-int xi_interface_close(void)
-{
- if ( privcmd_fd != -1 )
- {
- close(privcmd_fd);
- privcmd_fd = -1;
- }
- return 0;
-}
-
-
-#define CONSOLE_RING_CLEAR 1
-
-int xi_readconsolering(char *str, unsigned int max_chars, int clear)
-{
- int ret;
- dom0_op_t op;
-
- op.cmd = DOM0_READCONSOLE;
- op.u.readconsole.str = (unsigned long)str;
- op.u.readconsole.count = max_chars;
- op.u.readconsole.cmd = clear ? CONSOLE_RING_CLEAR : 0;
-
- if ( (ret = do_dom0_op(&op)) > 0 )
- str[ret] = '\0';
-
- return ret;
-}
-
+++ /dev/null
-/******************************************************************************
- * libxi_private.c
- *
- * Helper functions for the rest of the library.
- */
-
-#include "libxi_private.h"
-
-static int devmem_fd = -1;
-
-int init_pfn_mapper(void)
-{
- if ( (devmem_fd == -1) &&
- ((devmem_fd = open("/dev/mem", O_RDWR)) < 0) )
- {
- devmem_fd = -1;
- return -1;
- }
- return 0;
-}
-
-void *map_pfn(unsigned long pfn)
-{
- void *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE,
- MAP_SHARED, devmem_fd, pfn << PAGE_SHIFT);
- if ( vaddr == MAP_FAILED )
- return NULL;
- return vaddr;
-}
-
-void unmap_pfn(void *vaddr)
-{
- (void)munmap(vaddr, PAGE_SIZE);
-}
+++ /dev/null
-
-#ifndef __LIBXI_PRIVATE_H__
-#define __LIBXI_PRIVATE_H__
-
-typedef unsigned char u8;
-typedef unsigned short u16;
-typedef unsigned long u32;
-typedef unsigned long long u64;
-typedef signed char s8;
-typedef signed short s16;
-typedef signed long s32;
-typedef signed long long s64;
-
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <string.h>
-
-#include "xi.h"
-
-#include <asm-xeno/proc_cmd.h>
-#include <hypervisor-ifs/hypervisor-if.h>
-#include <hypervisor-ifs/dom0_ops.h>
-#include <hypervisor-ifs/vbd.h>
-
-#define _PAGE_PRESENT 0x001
-#define _PAGE_RW 0x002
-#define _PAGE_USER 0x004
-#define _PAGE_PWT 0x008
-#define _PAGE_PCD 0x010
-#define _PAGE_ACCESSED 0x020
-#define _PAGE_DIRTY 0x040
-#define _PAGE_PAT 0x080
-#define _PAGE_PSE 0x080
-#define _PAGE_GLOBAL 0x100
-
-
-#define L1_PAGETABLE_SHIFT 12
-#define L2_PAGETABLE_SHIFT 22
-
-#define ENTRIES_PER_L1_PAGETABLE 1024
-#define ENTRIES_PER_L2_PAGETABLE 1024
-
-#define PAGE_SHIFT L1_PAGETABLE_SHIFT
-#define PAGE_SIZE (1UL << PAGE_SHIFT)
-#define PAGE_MASK (~(PAGE_SIZE-1))
-
-typedef struct { unsigned long l1_lo; } l1_pgentry_t;
-typedef struct { unsigned long l2_lo; } l2_pgentry_t;
-
-#define l1_table_offset(_a) \
- (((_a) >> L1_PAGETABLE_SHIFT) & (ENTRIES_PER_L1_PAGETABLE - 1))
-#define l2_table_offset(_a) \
- ((_a) >> L2_PAGETABLE_SHIFT)
-
-#define ERROR(_m) \
- fprintf(stderr, "ERROR: %s\n", (_m))
-
-#define PERROR(_m) \
- fprintf(stderr, "ERROR: %s (%d = %s)\n", (_m), errno, strerror(errno))
-
-extern int privcmd_fd;
-static inline int do_privcmd(unsigned int cmd, unsigned long data)
-{
- return ioctl(privcmd_fd, cmd, data);
-}
-
-static inline int do_xen_hypercall(privcmd_hypercall_t *hypercall)
-{
- return do_privcmd(IOCTL_PRIVCMD_HYPERCALL, (unsigned long)hypercall);
-}
-
-static inline int do_dom0_op(dom0_op_t *op)
-{
- int ret = -1;
- privcmd_hypercall_t hypercall;
-
- op->interface_version = DOM0_INTERFACE_VERSION;
-
- hypercall.op = __HYPERVISOR_dom0_op;
- hypercall.arg[0] = (unsigned long)op;
-
- if ( mlock(op, sizeof(*op)) != 0 )
- goto out1;
-
- if ( (ret = do_xen_hypercall(&hypercall)) < 0 )
- {
- if ( errno == EACCES )
- fprintf(stderr, "Dom0 operation failed -- need to"
- " rebuild the user-space tool set?\n");
- goto out2;
- }
-
- ret = 0;
-
- out2: (void)munlock(op, sizeof(*op));
- out1: return ret;
-}
-
-static inline int do_network_op(network_op_t *op)
-{
- int ret = -1;
- privcmd_hypercall_t hypercall;
-
- hypercall.op = __HYPERVISOR_network_op;
- hypercall.arg[0] = (unsigned long)op;
-
- if ( mlock(op, sizeof(*op)) != 0 )
- goto out1;
-
- if ( (ret = do_xen_hypercall(&hypercall)) < 0 )
- goto out2;
-
- ret = 0;
-
- out2: (void)munlock(op, sizeof(*op));
- out1: return ret;
-}
-
-
-static inline int do_block_io_op(block_io_op_t *op)
-{
- int ret = -1;
- privcmd_hypercall_t hypercall;
-
- hypercall.op = __HYPERVISOR_block_io_op;
- hypercall.arg[0] = (unsigned long)op;
-
- if ( mlock(op, sizeof(*op)) != 0 )
- goto out1;
-
- if ( do_xen_hypercall(&hypercall) < 0 )
- goto out2;
-
- ret = 0;
-
- out2: (void)munlock(op, sizeof(*op));
- out1: return ret;
-}
-
-/*
- * PFN mapping.
- */
-int init_pfn_mapper(void);
-void *map_pfn(unsigned long pfn);
-void unmap_pfn(void *vaddr);
-
-#endif /* __LIBXI_PRIVATE_H__ */
+++ /dev/null
-/******************************************************************************
- * libxi_vbd.c
- *
- * API for manipulating and accessing per-domain virtual block devices.
- *
- * Copyright (c) 2003, K A Fraser.
- */
-
-#define _GNU_SOURCE
-#include "libxi_private.h"
-
-int xi_vbd_create(unsigned int domid, unsigned short vbdid, int writeable)
-{
- block_io_op_t op;
- op.cmd = BLOCK_IO_OP_VBD_CREATE;
- op.u.create_params.domain = domid;
- op.u.create_params.vdevice = vbdid;
- op.u.create_params.mode = VBD_MODE_R | (writeable ? VBD_MODE_W : 0);
- return do_block_io_op(&op);
-}
-
-
-int xi_vbd_destroy(unsigned int domid, unsigned short vbdid)
-{
- block_io_op_t op;
- op.cmd = BLOCK_IO_OP_VBD_DELETE;
- op.u.delete_params.domain = domid;
- op.u.delete_params.vdevice = vbdid;
- return do_block_io_op(&op);
-}
-
-
-int xi_vbd_add_extent(unsigned int domid,
- unsigned short vbdid,
- unsigned short real_device,
- unsigned long start_sector,
- unsigned long nr_sectors)
-{
- block_io_op_t op;
- op.cmd = BLOCK_IO_OP_VBD_ADD;
- op.u.add_params.domain = domid;
- op.u.add_params.vdevice = vbdid;
- op.u.add_params.extent.device = real_device;
- op.u.add_params.extent.start_sector = start_sector;
- op.u.add_params.extent.nr_sectors = nr_sectors;
- return do_block_io_op(&op);
-}
-
-
-int xi_vbd_delete_extent(unsigned int domid,
- unsigned short vbdid,
- unsigned short real_device,
- unsigned long start_sector,
- unsigned long nr_sectors)
-{
- block_io_op_t op;
- op.cmd = BLOCK_IO_OP_VBD_REMOVE;
- op.u.add_params.domain = domid;
- op.u.add_params.vdevice = vbdid;
- op.u.add_params.extent.device = real_device;
- op.u.add_params.extent.start_sector = start_sector;
- op.u.add_params.extent.nr_sectors = nr_sectors;
- return do_block_io_op(&op);
-}
-
-
-int xi_vbd_probe(unsigned int domid,
- unsigned short vbdid,
- unsigned int max_vbds,
- xi_vbd_t *vbds)
-{
- block_io_op_t op;
- xen_disk_info_t *xdi = &op.u.probe_params.xdi;
- int i, j, ret, allocsz = max_vbds * sizeof(xen_disk_t);
-
- op.cmd = BLOCK_IO_OP_VBD_PROBE;
- op.u.probe_params.domain = domid;
-
- xdi->max = max_vbds;
- xdi->disks = malloc(allocsz);
- xdi->count = 0;
-
- if ( (xdi->disks == NULL) || (mlock(xdi->disks, allocsz) != 0) )
- {
- if ( xdi->disks != NULL )
- free(xdi->disks);
- return -ENOMEM;
- }
-
- ret = do_block_io_op(&op);
-
- (void)munlock(xdi->disks, allocsz);
-
- if ( ret >= 0 )
- {
- for ( i = 0, j = 0; i < xdi->count; i++ )
- {
- if ( !(xdi->disks[i].info & XD_FLAG_VIRT) )
- continue;
-
- vbds[j].domid = xdi->disks[i].domain;
- vbds[j].vbdid = xdi->disks[i].device;
- vbds[j].flags = (xdi->disks[i].info & XD_FLAG_RO) ?
- 0 : XI_VBDF_WRITEABLE;
- vbds[j].nr_sectors = xdi->disks[i].capacity;
-
- j++;
- }
-
- ret = j;
- }
-
- free(xdi->disks);
-
- return ret;
-}
+++ /dev/null
-/******************************************************************************
- * libxi_vif.c
- *
- * API for manipulating and accessing per-network-interface parameters.
- *
- * Copyright (c) 2003, K A Fraser.
- */
-
-#include "libxi_private.h"
-
-int xi_vif_scheduler_set(unsigned int domid,
- unsigned int vifid,
- xi_vif_sched_params_t *params)
-{
- network_op_t netop;
- netop.cmd = NETWORK_OP_VIFSETPARAMS;
- netop.u.vif_setparams.domain = domid;
- netop.u.vif_setparams.vif = vifid;
- netop.u.vif_setparams.credit_bytes = params->credit_bytes;
- netop.u.vif_setparams.credit_usec = params->credit_usec;
- return do_network_op(&netop);
-}
-
-
-int xi_vif_scheduler_get(unsigned int domid,
- unsigned int vifid,
- xi_vif_sched_params_t *params)
-{
- network_op_t netop;
- int rc;
-
- netop.cmd = NETWORK_OP_VIFGETINFO;
- netop.u.vif_getinfo.domain = domid;
- netop.u.vif_getinfo.vif = vifid;
-
- if ( (rc = do_network_op(&netop)) >= 0 )
- {
- params->credit_bytes = netop.u.vif_getinfo.credit_bytes;
- params->credit_usec = netop.u.vif_getinfo.credit_usec;
- }
-
- return rc;
-}
-
-
-int xi_vif_stats_get(unsigned int domid,
- unsigned int vifid,
- xi_vif_stats_t *stats)
-{
- network_op_t netop;
- int rc;
-
- netop.cmd = NETWORK_OP_VIFGETINFO;
- netop.u.vif_getinfo.domain = domid;
- netop.u.vif_getinfo.vif = vifid;
-
- if ( (rc = do_network_op(&netop)) >= 0 )
- {
- stats->tx_bytes = netop.u.vif_getinfo.total_bytes_sent;
- stats->tx_pkts = netop.u.vif_getinfo.total_packets_sent;
- stats->rx_bytes = netop.u.vif_getinfo.total_bytes_received;
- stats->rx_pkts = netop.u.vif_getinfo.total_packets_received;
- }
-
- return rc;
-}
+++ /dev/null
-Summary: Xen control interface library
-Name: xen-internal-library
-Version: 1.2
-Release: 1
-License: Xen
-Group: Xen
-BuildRoot: %{staging}
-%description
-Library to make it easier to access the Xen control interfaces.
-
-%pre
-%preun
-%install
-install -m 0755 -d $RPM_BUILD_ROOT/lib
-install -m 0755 libxi.a $RPM_BUILD_ROOT/lib/libxi.a
-install -m 0755 libxi.so $RPM_BUILD_ROOT/lib/libxi.so
-install -m 0755 -d $RPM_BUILD_ROOT/include
-install -m 0644 xi.h $RPM_BUILD_ROOT/include/xi.h
-%clean
-%post
-%postun
-%files
-%defattr(-,root,root)
-%dir /lib
-/lib/libxi.a
-/lib/libxi.so
-%dir /include
-/include/xi.h
+++ /dev/null
-/******************************************************************************
- * xi.h
- *
- * A library for low-level access to the Xen control interfaces.
- *
- * Copyright (c) 2003, K A Fraser.
- */
-
-#ifndef __XI_H__
-#define __XI_H__
-
-int xi_interface_open(void);
-int xi_interface_close(void);
-
-typedef struct {
- unsigned int domid;
- unsigned int cpu;
- int has_cpu;
- int stopped;
- unsigned long nr_pages;
- unsigned long long cpu_time;
-#define XI_DOMINFO_MAXNAME 16
- char name[XI_DOMINFO_MAXNAME];
-} xi_dominfo_t;
-
-int xi_domain_create(unsigned int mem_kb, const char *name);
-int xi_domain_start(unsigned int domid);
-int xi_domain_stop(unsigned int domid);
-int xi_domain_destroy(unsigned int domid, int force);
-int xi_domain_getinfo(unsigned int first_domid,
- unsigned int max_doms,
- xi_dominfo_t *info);
-
-int xi_linux_save(unsigned int domid, const char *state_file, int verbose);
-int xi_linux_restore(const char *state_file, int verbose);
-int xi_linux_build(unsigned int domid,
- const char *image_name,
- const char *ramdisk_name,
- const char *cmdline,
- int verbose);
-
-int xi_bvtsched_global_set(unsigned long ctx_allow);
-int xi_bvtsched_domain_set(unsigned int domid,
- unsigned long mcuadv,
- unsigned long warp,
- unsigned long warpl,
- unsigned long warpu);
-
-typedef struct {
- unsigned long credit_bytes;
- unsigned long credit_usec;
-} xi_vif_sched_params_t;
-
-typedef struct {
- unsigned long long tx_bytes, tx_pkts;
- unsigned long long rx_bytes, rx_pkts;
-} xi_vif_stats_t;
-
-int xi_vif_scheduler_set(unsigned int domid,
- unsigned int vifid,
- xi_vif_sched_params_t *params);
-int xi_vif_scheduler_get(unsigned int domid,
- unsigned int vifid,
- xi_vif_sched_params_t *params);
-int xi_vif_stats_get(unsigned int domid,
- unsigned int vifid,
- xi_vif_stats_t *stats);
-
-typedef struct {
-#define XI_VBDDOM_PROBE_ALL (~0U)
- unsigned int domid;
- unsigned short vbdid;
-#define XI_VBDF_WRITEABLE (1<<0)
- unsigned long flags;
- unsigned long nr_sectors;
-} xi_vbd_t;
-
-
-int xi_vbd_create(unsigned int domid, unsigned short vbdid, int writeable);
-int xi_vbd_destroy(unsigned int domid, unsigned short vbdid);
-int xi_vbd_add_extent(unsigned int domid,
- unsigned short vbdid,
- unsigned short real_device,
- unsigned long start_sector,
- unsigned long nr_sectors);
-int xi_vbd_delete_extent(unsigned int domid,
- unsigned short vbdid,
- unsigned short real_device,
- unsigned long start_sector,
- unsigned long nr_sectors);
-int xi_vbd_probe(unsigned int domid,
- unsigned short vbdid,
- unsigned int max_vbds,
- xi_vbd_t *vbds);
-
-int xi_readconsolering(char *str, unsigned int max_chars, int clear);
-
-
-#endif /* __XI_H__ */